asembler-dla-procesorow-arm-podrecznik-programisty-william-hohl-Helion.pl.pdf

July 28, 2017 | Author: Jarosław Biszczuk | Category: Arm Architecture, Compiler, Programmer, Assembly Language, Computer Programming
Share Embed Donate


Short Description

Download asembler-dla-procesorow-arm-podrecznik-programisty-william-hohl-Helion.pl.pdf...

Description

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

Tytuá oryginaáu: ARM Assembly Language: Fundamentals and Techniques Táumaczenie: Paweá Gonera ISBN: 978-83-246-9322-1 © 2009 by ARM (UK). All rights reserved. Authorized translation from English language edition published by CRC Press, part of Taylor & Francis Group LLC. Polish edition copyright © 2014 by Helion S.A. All rights reserved. All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording or by any information storage retrieval system, without permission from the Publisher. Wszelkie prawa zastrzeĪone. Nieautoryzowane rozpowszechnianie caáoĞci lub fragmentu niniejszej publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii metodą kserograficzną, fotograficzną, a takĪe kopiowanie ksiąĪki na noĞniku filmowym, magnetycznym lub innym powoduje naruszenie praw autorskich niniejszej publikacji. Wszystkie znaki wystĊpujące w tekĞcie są zastrzeĪonymi znakami firmowymi bądĨ towarowymi ich wáaĞcicieli. Autor oraz Wydawnictwo HELION doáoĪyli wszelkich staraĔ, by zawarte w tej ksiąĪce informacje byáy kompletne i rzetelne. Nie biorą jednak Īadnej odpowiedzialnoĞci ani za ich wykorzystanie, ani za związane z tym ewentualne naruszenie praw patentowych lub autorskich. Autor oraz Wydawnictwo HELION nie ponoszą równieĪ Īadnej odpowiedzialnoĞci za ewentualne szkody wynikáe z wykorzystania informacji zawartych w ksiąĪce. Wydawnictwo HELION ul. KoĞciuszki 1c, 44-100 GLIWICE tel. 32 231 22 19, 32 230 98 63 e-mail: [email protected] WWW: http://helion.pl (ksiĊgarnia internetowa, katalog ksiąĪek) Drogi Czytelniku! JeĪeli chcesz oceniü tĊ ksiąĪkĊ, zajrzyj pod adres http://helion.pl/user/opinie/asarpp_ebook MoĪesz tam wpisaü swoje uwagi, spostrzeĪenia, recenzjĊ.

x Poleć książkę na Facebook.com

x Księgarnia internetowa

x Kup w wersji papierowej

x Lubię to! » Nasza społeczność

x Oceń książkę





Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

Dla Christophera, Chase i Alice, którzy piekli mi ciasteczka

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

Spis treĂci Wprowadzenie ................................................................................................ 11 PodziĊkowania ................................................................................................ 15 Informacja o oprogramowaniu ........................................................................ 17 Autor ............................................................................................................... 19 Rozdziaá 1. Przegląd systemów komputerowych ............................................................... 21 1.1. WstĊp ...................................................................................................... 21 1.2. Historia architektury RISC ..................................................................... 23 1.2.1. Początki firmy ARM ................................................................... 25 1.2.2. Powstanie ARM Ltd. ................................................................... 26 1.2.3. ARM obecnie .............................................................................. 28 1.3. Urządzenia liczące .................................................................................. 29 1.4. Systemy liczbowe ................................................................................... 31 1.5. Reprezentacja liczb i znaków ................................................................. 34 1.5.1. Reprezentacja liczb caákowitych ................................................. 34 1.5.2. Reprezentacja zmiennoprzecinkowa ........................................... 37 1.5.3. Reprezentacja znakowa ............................................................... 39 1.6. Táumaczenie bitów na rozkazy ............................................................... 39 1.7. NarzĊdzia ................................................................................................ 41 1.8. ûwiczenia ............................................................................................... 43 Rozdziaá 2. Model programowania ARM7TDMI .............................................................. 47 2.1. WstĊp ...................................................................................................... 47 2.2. Typy danych ........................................................................................... 47 2.3. Tryby procesora ...................................................................................... 48 2.4. Rejestry ................................................................................................... 49 2.5. Rejestry stanu programu ......................................................................... 51 2.5.1. Bity kontrolne .............................................................................. 51 2.5.2. Bity trybu .................................................................................... 51 2.6. Tabela wektorów .................................................................................... 52 2.7. ûwiczenia ............................................................................................... 53 Rozdziaá 3. Pierwsze programy .......................................................................................... 55 3.1. WstĊp ...................................................................................................... 55 3.2. Program 1.: Przesuwanie danych ............................................................ 56 3.2.1. Uruchamianie kodu ..................................................................... 57 3.2.2. Sprawdzanie zawartoĞci rejestrów i pamiĊci ............................... 58

5 Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

6

Spis treĂci

3.3. 3.4. 3.5. 3.6.

Program 2.: Obliczanie silni ................................................................... 58 Program 3.: Zamiana zawartoĞci rejestrów ............................................. 61 Wskazówki dla programistów ................................................................ 61 ûwiczenia ............................................................................................... 63

Rozdziaá 4. Dyrektywy i zasady korzystania z asemblera .................................................. 65 4.1. WstĊp ...................................................................................................... 65 4.2. Struktura moduáów jĊzyka asemblera ..................................................... 65 4.3. Predefiniowane nazwy rejestrów ............................................................ 68 4.4. CzĊsto uĪywane dyrektywy .................................................................... 68 4.4.1. AREA — definicja bloku danych lub kodu ................................. 69 4.4.2. RN — definicja nazwy rejestru ................................................... 70 4.4.3. EQU — definicja symbolu dla staáej numerycznej ..................... 70 4.4.4. ENTRY — deklaracja punktu wejĞcia ........................................ 71 4.4.5. DCB, DCW i DCD — przydziaá pamiĊci i okreĞlenie zawartoĞci ................................................................ 71 4.4.6. ALIGN — wyrównanie danych lub kodu do odpowiedniej granicy ............................................................. 72 4.4.7. SPACE — rezerwacja bloku pamiĊci .......................................... 73 4.4.8. LTORG — przypisanie punktu startowego puli literaáów .......... 73 4.4.9. END — koniec pliku Ĩródáowego ............................................... 74 4.5. Makra ...................................................................................................... 74 4.6. Pozostaáe funkcje asemblera ................................................................... 76 4.6.1. Operacje asemblera ..................................................................... 76 4.6.2. Literaáy ........................................................................................ 77 4.7. ûwiczenia ............................................................................................... 77 Rozdziaá 5. àadowanie, zapisywanie i adresowanie .......................................................... 79 5.1. WstĊp ...................................................................................................... 79 5.2. PamiĊü .................................................................................................... 79 5.3. àadowanie i zapisywanie — instrukcje .................................................. 82 5.4. Operandy adresowania ........................................................................... 85 5.4.1. Adresowanie preindeksowane ..................................................... 85 5.4.2. Adresowanie postindeksowane ................................................... 86 5.5. Porządek bajtów ..................................................................................... 88 5.5.1. Zmiana porządku bajtów ............................................................. 89 5.5.2. Definiowanie obszarów pamiĊci ................................................. 90 5.6. ûwiczenia ............................................................................................... 91 Rozdziaá 6. Staáe i pule literaáów ....................................................................................... 95 6.1. WstĊp ...................................................................................................... 95 6.2. Schemat rotacji ARM ............................................................................. 95 6.3. àadowanie staáych do rejestrów ............................................................. 98 6.4. àadowanie adresów do rejestrów ......................................................... 101 6.5. ûwiczenia ............................................................................................. 105

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

Spis treĂci

7

Rozdziaá 7. Operacje logiczne i arytmetyczne ................................................................. 107 7.1. WstĊp .................................................................................................... 107 7.2. Znaczniki i ich wykorzystywanie ......................................................... 107 7.2.1. Znacznik N ................................................................................ 108 7.2.2. Znacznik V ................................................................................ 108 7.2.3. Znacznik Z ................................................................................ 109 7.2.4. Znacznik C ................................................................................ 109 7.3. Instrukcje porównania .......................................................................... 109 7.4. Operacje przetwarzania danych ............................................................ 110 7.4.1. Operacje logiczne ...................................................................... 111 7.4.2. PrzesuniĊcia i rotacje ................................................................. 112 7.4.3. Dodawanie i odejmowanie ........................................................ 117 7.4.4. MnoĪenie ................................................................................... 119 7.4.5. MnoĪenie przez staáą ................................................................. 120 7.4.6. Dzielenie ................................................................................... 121 7.5. Notacja uáamkowa ................................................................................ 122 7.6. ûwiczenia ............................................................................................. 127 Rozdziaá 8. PĊtle i skoki ................................................................................................... 131 8.1. WstĊp .................................................................................................... 131 8.2. Skoki ..................................................................................................... 132 8.3. PĊtle ...................................................................................................... 135 8.3.1. PĊtle while ................................................................................. 135 8.3.2. PĊtle for ..................................................................................... 136 8.3.3. PĊtle do ... while ........................................................................ 139 8.4. WiĊcej na temat znaczników ................................................................ 139 8.5. Wykonanie warunkowe ........................................................................ 140 8.6. Kodowanie w linii prostej ..................................................................... 142 8.7. ûwiczenia ............................................................................................. 143 Rozdziaá 9. Tablice .......................................................................................................... 145 9.1. WstĊp .................................................................................................... 145 9.2. Tablice wyszukiwania .......................................................................... 145 9.3. Tablice skoków ..................................................................................... 149 9.4. Wyszukiwanie binarne ......................................................................... 150 9.5. ûwiczenia ............................................................................................. 153 Rozdziaá 10. Podprogramy i stosy ...................................................................................... 157 10.1. WstĊp .................................................................................................... 157 10.2. Stos ....................................................................................................... 158 10.2.1.Instrukcje LDM i STM .............................................................. 158 10.2.2.Stosy peáne, puste, rosnące i malejące ....................................... 160 10.3. Podprogramy ........................................................................................ 162 10.4. Przekazywanie parametrów do podprogramów .................................... 163 10.4.1.Przekazywanie parametrów przez rejestry ................................ 163 10.4.2.Przekazywanie parametrów przez referencjĊ ............................ 165 10.4.3.Przekazywanie parametrów na stosie ........................................ 167

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

8

Spis treĂci

10.5. Standard ARM APCS ........................................................................... 168 10.6. ûwiczenia ............................................................................................. 169 Rozdziaá 11. Obsáuga wyjątków ........................................................................................ 173 11.1. WstĊp .................................................................................................... 173 11.2. Przerwania ............................................................................................ 173 11.3. BáĊdy .................................................................................................... 174 11.4. Sekwencja wyjątku w procesorze ......................................................... 175 11.5. Tablica wektorów ................................................................................. 176 11.6. Handlery wyjątków .............................................................................. 179 11.7. Priorytety wyjątków ............................................................................. 180 11.8. Procedury obsáugi wyjątków ................................................................ 181 11.8.1.Wyjątek Reset ........................................................................... 181 11.8.2.Niezdefiniowana instrukcja ....................................................... 181 11.8.3.Przerwania ................................................................................. 185 11.8.4.BáĊdy przerwania ....................................................................... 194 11.8.5.SWI ........................................................................................... 195 11.9. ûwiczenia ............................................................................................. 196 Rozdziaá 12. Urządzenia peryferyjne z odwzorowaną pamiĊcią ........................................ 199 12.1. WstĊp .................................................................................................... 199 12.2. LPC2104 ............................................................................................... 200 12.2.1.Ukáad UART ............................................................................. 200 12.2.2.Mapa pamiĊci ............................................................................ 200 12.2.3.Konfigurowanie ukáadu UART ................................................. 202 12.2.4.Zapis danych do UART ............................................................. 205 12.2.5.Kompletny kod .......................................................................... 206 12.2.6.Uruchamianie aplikacji .............................................................. 207 12.3. Ukáad LPC2132 .................................................................................... 208 12.3.1.Konwerter C/A .......................................................................... 208 12.3.2.Mapa pamiĊci ............................................................................ 210 12.3.3.Konfiguracja konwertera C/A ................................................... 210 12.3.4.Generowanie fali sinusoidalnej ................................................. 210 12.3.5.Kompletny kod .......................................................................... 212 12.3.6.Uruchamianie kodu ................................................................... 214 12.4. ûwiczenia ............................................................................................. 214 Rozdziaá 13. THUMB ........................................................................................................ 217 13.1. WstĊp .................................................................................................... 217 13.2. Instrukcje THUMB ............................................................................... 218 13.3. RóĪnice pomiĊdzy ARM i THUMB ..................................................... 220 13.4. Implementacja i uĪycie THUMB .......................................................... 221 13.4.1.Modyfikacje procesora .............................................................. 221 13.4.2.Przeáączanie siĊ pomiĊdzy stanem ARM i THUMB ................. 221 13.5. Kompilacja dla THUMB ...................................................................... 223 13.6. ûwiczenia ............................................................................................. 225

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

Spis treĂci

9

Rozdziaá 14. àączenie C i asemblera ................................................................................. 227 14.1. WstĊp .................................................................................................... 227 14.2. Wstawki asemblerowe .......................................................................... 227 14.2.1.Skáadnia wstawek asemblerowych ............................................ 230 14.2.2.Ograniczenia dziaáania wstawek asemblerowych ..................... 231 14.3. Asembler wbudowany .......................................................................... 232 14.3.1.Skáadnia asemblera wbudowanego ............................................ 234 14.3.2.Ograniczenia dziaáania asemblera wbudowanego ..................... 234 14.4. Wywoáania pomiĊdzy C i asemblerem ................................................. 234 14.5. ûwiczenia ............................................................................................. 236 Dodatek A

Zbiór instrukcji ARM V4T ........................................................................... 239

Dodatek B

Korzystanie z narzĊdzi Keil .......................................................................... 339 B.1. WstĊp .................................................................................................... 339 B.2. Tworzenie projektu i wybór urządzenia ............................................... 339 B.3. Tworzenie kodu aplikacji ..................................................................... 341 B.4. Budowanie projektu i uruchamianie kodu ............................................ 343

Dodatek C

Kody znaków ASCII ..................................................................................... 345 Glosariusz ..................................................................................................... 347 OdnoĞniki ...................................................................................................... 349 Skorowidz ..................................................................................................... 350

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

10

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

Spis treĂci

Wprowadzenie W ostatnich 20 latach pojawiáo siĊ w branĪy przeĞwiadczenie, Īe oprogramowanie staje siĊ coraz bardziej zaawansowane, a narzĊdzia uĪywane do programowania komputerów zbliĪają siĊ do punktu, w którym programista bĊdzie miaá ogromne problemy, Īeby wyprodukowaü lepszy lub bardziej efektywny kod niĪ kompilator. Byü moĪe jest to prawda. W przypadku nowoczesnych kompilatorów analizy porównawcze pokazują ogromne postĊpy w gĊstoĞci kodu, wykorzystaniu rejestrów i przepustowoĞci. Wiele uniwersytetów przestaáo uczyü asemblera, poniewaĪ kompilatory są znacznie lepsze, niĪ byáy 20 lat temu. Gdy studenci zaczynają studia na informatyce czy inĪynierii, od razu programują w jĊzykach wysokiego poziomu, takich jak C czy Java. Mogą zdobyü tytuá magistra, nie tworząc ani jednego wiersza kodu maszynowego. PoniewaĪ wiedzą, Īe oprogramowanie obsáuĪy wszystkie szczegóáy, mogą nigdy nie poznaü sposobu, w jaki procesory manipulują zerami i jedynkami. Trudno jednak zignorowaü to, co dzieje siĊ w branĪy. Z 13 miliardów ukáadów mikroprocesorowych sprzedanych w roku 2007 niemal 3 miliardy bazowaáy na rozwiązaniach ARM. WiĊkszoĞü z nich pracuje jako procesory wbudowane, sterujące niewielkimi ukáadami znajdującymi siĊ w kuchence mikrofalowej, samochodzie, telefonie komórkowym, lodówce, zabawkach i w niemal kaĪdym urządzeniu przenoĞnym. Rynek ten jest bardzo wraĪliwy na koszty — koszt jednego pinu w mikrokontrolerze moĪe wynosiü 5 groszy w jednym ukáadzie, ale przy budowie 20 milionów urządzeĔ jako producent zdecydowaábym siĊ zaoszczĊdziü te 5 groszy. Co wiĊcej, cena ukáadów pamiĊci jest dziesiĊciokrotnie wyĪsza niĪ cena procesora, wiĊc jeĪeli uda Ci siĊ tak zmodyfikowaü projekt, Īe bĊdzie wymagaá tylko jednego ukáadu DRAM zamiast dwóch, to Twój kierownik na pewno zgodzi siĊ na Twój awans. Aby osiągnąü taki poziom optymalizacji, programiĞci zazwyczaj korzystają zarówno z kodu wysokiego poziomu, jak i z kodu maszynowego wymaganego przy optymalizacji starannie wybranych podprogramów. Kodowanie nie odbywa siĊ jednak tak jak w latach 70. czy 80. ubiegáego stulecia, kiedy duĪe projekty byáy pisane w asemblerze przez caáe zespoáy programistów. Zamiast tego czasami decyduje siĊ, Īe na przykáad sterownik urządzenia musi byü zintegrowany z kodem C lub C++, a dogáĊbna znajomoĞü asemblera znacznie uáatwia to zadanie. W rzeczywistoĞci programista piszący kod w dowolnym jĊzyku skorzysta na zrozumieniu zasad dziaáania komputera. W branĪy urządzeĔ wbudowanych jest to szczególnie waĪne. Istnieje jeszcze wiĊcej waĪnych powodów, aby nauczyü siĊ asemblera. ProgramiĞci tworzący kompilatory muszą dokáadnie wiedzieü, jak dziaáa maszyna, dla której piszą kod, jaka jest jej architektura, zestaw instrukcji i model programowania. ProgramiĞci aplikacji piszący rĊcznie optymalizowane czasowo podprogramy muszą znaü asemblera. OkreĞlone funkcje procesorów są dostĊpne wyáącznie za pomocą natywnych instrukcji sprzĊtowych, na przykáad operacji matematycznych z nasyceniem lub wykorzystania koprocesorów. InĪynierowie sprzĊtowcy, którzy projektują nastĊpne generacje mikroprocesorów i mikrokontrolerów, muszą wiedzieü, jak one dziaáają na najniĪszym poziomie. Trudno wyobraziü sobie inĪyniera jakoĞci testującego ukáad przewidywania skoków, który nie potrafi pisaü w asemblerze. Donald Knuth

11 Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

12

Wprowadzenie

powiedziaá kiedyĞ: „KaĪda osoba, która interesuje siĊ nieco powaĪniej komputerami, powinna dobrze znaü jĊzyk maszynowy, poniewaĪ jest to podstawowy element dziaáania komputera” (Knuth 1973). W lutym 2008 roku Arm Holding ogáosiá, Īe jego partnerzy sprzedali 10 miliardów ukáadów ARM, uĪywanych w zastosowaniach o niskim poborze mocy, np. w kontrolerach dysków twardych, telefonach komórkowych, odtwarzaczach MP3 i aparatach cyfrowych. PoniewaĪ oczekiwano, Īe do roku 2011 sprzedane zostanie 268 milionów osobistych odtwarzaczy muzycznych, a sprzedaĪ telefonów komórkowych przekracza miliard rocznie, to wydaje siĊ, Īe liczba ofert pracy dla programistów, którzy znają nie tylko jĊzyki wysokiego poziomu, bĊdzie rosáa. Co wiĊcej, nawet jeĪeli jesteĞ programistą wysokiego poziomu korzystającym z C lub C++, to obniĪyü koszty i poprawiü wydajnoĞü moĪesz wyáącznie przez bezpoĞrednie sterowanie sprzĊtem za pomocą asemblera. Byü moĪe ta ksiąĪka jest spóĨniona o 14 lat, poniewaĪ ARM7TDMI zostaá pokazany Ğwiatu w roku 1996, ale nie byáo dla niego podrĊczników. Choü są dostĊpne dobre podrĊczniki na temat sprzĊtu, takie jak ksiąĪka Steve’a Furbera na temat projektowania SoC (Furber 2000), to studenci nieznający asemblera mogą mieü problemy z materiaáem kursu trwającego jeden semestr. Ostatnia ksiąĪka traktująca o asemblerze dla procesorów ARM zostaáa napisana w roku 1993, gdy ARM6 próbowaá zdobywaü wzglĊdnie nowy rynek osobistych urządzeĔ elektronicznych o niskim poborze mocy. Studenci czĊsto uczą siĊ asemblera starych 8-bitowych systemów, poniewaĪ wmawia im siĊ, Īe systemy 32-bitowe są zbyt trudne na naukĊ asemblera, poza tym nie ma zbyt wielu pozycji dla studentów na temat asemblera ARM. Jak siĊ jednak okazuje, znacznie áatwiej jest nauczyü siĊ asemblera dla komputerów 32-bitowych, poniewaĪ maszyny 8-bitowe wymagają áączenia ze sobą danych i rejestrów, aby uzyskaü coĞ bardziej uĪytecznego. Od roku 1994 ARM wprowadziá piĊü nowych generacji procesorów, z których ostatnia nosi nazwĊ Cortex, i choü miáo byáoby zaczynaü naukĊ asemblera od wykorzystania procesora Cortex-A8, to mogáoby to byü podobne do nauki jazdy w samochodach marki Ferrari (co chyba nie jest najlepszym pomysáem — choü to tylko moja opinia). W tej ksiąĪce staramy siĊ zacząü bliĪej początku, korzystając ze zbioru instrukcji ARM Version 4T, który jest dostĊpny w procesorze ARM7TDMI. Dlaczego? Dla początkujących waĪne jest, Īe na rynku jest ogromna liczba mikrokontrolerów bazujących na ARM7, wiĊc bardzo áatwo moĪna kupiü urządzenie ze sporą gamą moĪliwoĞci i ukáadów peryferyjnych. RównieĪ mikroprocesory Version 5TE, 6 i 7 obsáugują instrukcje Version 4T, wiĊc nauczenie siĊ podstaw pozwala na áatwiejsze przeskoczenie do bardziej rozbudowanych architektur. DostĊpne są równieĪ dobre pozycje na temat pisania zoptymalizowanych podprogramów aplikacji, takich jak algorytmy DSP, grafika czy przetwarzanie dĨwiĊku (Oshana 2006; Sloss, Symes i Wright 2004). JeĪeli jednak nie nauczyáeĞ siĊ podstaw, przeskoczenie od zera do tych zaawansowanych pozycji jest niemal niemoĪliwe. Ta ksiąĪka jest napisana przede wszystkim dla studentów drugiego i trzeciego roku, mających pewną wiedzĊ na temat logiki cyfrowej, programowania wysokiego poziomu i arytmetyki binarnej. Nie jest ona pomyĞlana jako kolejny tom na temat architektury komputerów czy projektowania sprzĊtowo-programowego, poniewaĪ tematy te są perfekcyjnie przedstawione w innych ksiąĪkach. Zadaniem tej ksiąĪki jest nie tylko nauczenie máodych programistów asemblera, ma ona równieĪ sáuĪyü im jako poradnik w ich dalszym rozwoju. Choü czĊĞü przedstawionego tu materiaáu moĪna znaleĨü w innych dokumentach na temat ARM, to jednak trzeba wiedzieü, gdzie ich szukaü, a czasami herkulesowy wysiáek odszukania wáaĞciwego rozwiązania w masie dokumentacji skutecznie zniechĊca do nauki asemblera.

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

Wprowadzenie

13

W pierwszej czĊĞci ksiąĪki przedstawiamy nieco podstaw dziaáania komputerów. Rozdziaá 1. jest bardzo krótkim przeglądem systemów komputerowych, prezentuje takĪe historiĊ firmy ARM doáączoną do dyskusji na temat architektury RISC. Rozdziaá ten zawiera ponadto opis systemów liczbowych, które naleĪy dobrze opanowaü przed przejĞciem do dalszych rozdziaáów. Rozdziaá 2. zawiera krótki opis modelu programowania — podobnie nowego kierowcĊ uczymy, gdzie jest sprzĊgáo, pedaá gazu i kierownica. W rozdziale 3. prezentujemy kilka prostych programów, a Īeby moĪna byáo uruchomiü kod, wprowadzamy podstawowe dyrektywy i pokazujemy, jak wyglądają instrukcje ARM. Rozdziaá 4. prezentuje wiĊkszoĞü dyrektyw, jakie są potrzebne czytelnikowi. Nie trzeba siĊ ich uczyü na pamiĊü. Tematem nastĊpnego rozdziaáu jest napisanie sensownego programu asemblera. WiĊkszoĞü instrukcji áadowania i zapisywania jest przedstawiona w rozdziale 5., z wyjątkiem instrukcji wielokrotnego áadowania i zapisu, które są opisane w rozdziale 10. Tematem rozdziaáu 6. jest tworzenie staáych w kodzie, jak równieĪ tworzenie pul literaáów i korzystanie z nich. Jeden z wiĊkszych rozdziaáów, rozdziaá 7., „Operacje logiczne i arytmetyczne”, przedstawia wszystkie operacje arytmetyczne. Zawiera teĪ dodatkowy podrozdziaá na temat notacji uáamkowej. PoniewaĪ niemal nigdy nie uczymy tego studentów, warto wprowadziü te koncepcje. JeĪeli kurs jest intensywny, moĪna pominąü ten materiaá, jednak temat ten jest poruszany w kilku innych rozdziaáach, na przykáad w rozdziale 9. przy okazji przedstawiania tabeli sinusów. W rozdziale 8. zostaáo przedstawione zagadnienie skoków oraz wykonywania warunkowego. Po przedstawieniu podstaw w pozostaáych rozdziaáach zajmujemy siĊ rzeczywistymi zastosowaniami asemblera i sytuacjami, z którymi spotykają siĊ programiĞci. W rozdziale 9. prezentujemy krótko tablice i listy. W rozdziale 10., poĞwiĊconym podprogramom i stosom, przedstawiamy instrukcje wielokrotnego áadowania i zapisywania oraz metody przekazywania parametrów do funkcji. W rozdziale 11. omawiamy wyjątki i podprogramy usáugowe. PoniewaĪ w ksiąĪce skáaniamy siĊ ku uĪyciu modeli symulacyjnych mikrokontrolerów, w rozdziale 12. przedstawiamy urządzenia peryferyjne i sposób ich programowania. W rozdziale 13. omawiamy skompresowany zbiór instrukcji o nazwie THUMB®. Ostatni temat, mieszanie jĊzyka C i asemblera, jest prezentowany w rozdziale 14. i moĪe byü wykorzystany, jeĪeli studenci są zainteresowani tą techniką. KsiąĪka ta jest pomyĞlana jako podrĊcznik i materiaá referencyjny, wiĊc dodatek A zawiera opis wszystkich instrukcji Version 4T. Dodatek B jest wprowadzeniem do uĪycia Ğrodowiska RealView Microcontroller Development Kit firmy Keil, dostĊpnego na stronie http://www.keil. com/demo. Warto go przeczytaü przed rozpoczĊciem kodowania. W dodatku C znajduje siĊ tablica znaków ASCII. Kurs o dáugoĞci jednego semestru (16 tygodni) powinien obejmowaü rozdziaáy od 1. do 11. W zaleĪnoĞci od tego, jak dokáadnie ma zostaü omówiony materiaá, informacje z rozdziaáów 12. do 14. powinny byü przedstawione w caáoĞci lub bez wchodzenia w szczegóáy. Instrukcje THUMB moĪna omówiü, jeĞli zostanie trochĊ wolnego czasu. W przypadku kursu caáorocznego warto zająü siĊ materiaáem z caáej ksiąĪki i poĞwiĊciü wiĊcej czasu na üwiczenia.

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

14

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

Wprowadzenie

PodziÚkowania KsiąĪka ta jest efektem lat pracy wielu inĪynierów. Choü widnieje na niej moje nazwisko, to jednak przedstawiony materiaá nie wyszedá jedynie spod mojego pióra, ale zostaá opracowany takĪe przez innych pracowników firmy ARM, którzy zajmują siĊ szkoleniami, dokumentacją i wsparciem. Sama ksiąĪka powstaáa u bardzo utalentowanego wydawcy. Dlatego muszĊ podziĊkowaü wielu osobom za wsparcie. Zaczynając od firmy ARM, pragnĊ podziĊkowaü Chrisowi Hinssowi, który przez niemal 20 lat okazywaá mi pomoc i przyjaĨĔ, a takĪe tolerowaá moje narzekania do momentu, gdy zasugerowaá napisanie tej ksiąĪki — prawdopodobnie po to, abym przestaá jĊczeü, Īe nie mam odpowiedniego podrĊcznika na zajĊcia z podstaw asemblera. Dwie kolejne osoby zajmujące siĊ początkową edycją i koĔcową korektą, bez których ksiąĪka ta nie mogáaby powstaü, to Joseph Bungo i Chris Shore. Sue Goznie muszĊ podziĊkowaü za ekspertyzĊ prawną i dopracowanie szczegóáów kontraktu, co byáo szczególnie waĪne z powodu bardzo napiĊtych terminów. Anne-Marie Miller, Steve Taylor i Stuart Waldron, specjaliĞci komunikacji z naszej firmy, opracowali Ğwietną grafikĊ na okáadkĊ, pomagali teĪ przy niektórych rysunkach i diagramach. Zadaniem Stuarta Smarta z dziaáu wydawnictw technicznych byáo dopilnowanie, aby stare informacje z początkowej wersji podrĊcznika Architectural Reference Manual nie znalazáy siĊ w tej ksiąĪce. Pozwoliáem sobie poĪyczyü kilka diagramów, jak równieĪ czĊĞü tekstów z dokumentacji Keil, RVDS i starych podrĊczników asemblera, wiĊc jestem dáuĪnikiem caáego dziaáu wsparcia i szkoleĔ ARM. Chciaábym podziĊkowaü im za ciĊĪką pracĊ przy pisaniu tych wszystkich materiaáów komercyjnych ARM. JeĪeli pominąáem jakieĞ zagadnienia związane z architekturą, to jest to wina jedynego kolegi z ARM, który byá na tyle miáy, Īe wykonaá korektĊ ksiąĪki, Gerarda Williamsa. BĊdĊ musiaá równieĪ zaprosiü do baru Paula Elbro, kierownika generalnego z dziaáu usáug, i podziĊkowaü mu za zgodĊ na realizacjĊ tego projektu. Chciaábym równieĪ podziĊkowaü zewnĊtrznym redaktorom, J.S. Hallowi z Georgia Tech (który zasugerowaá kolejnoĞü rozdziaáów), Markowi McDermottowi z University of Texas w Austin, Jamesowi Peckolowi z University of Washington, Gregowi Petersonowi z University of Tennessee oraz Victorowi Nelsonowi z Auburn University. Zamiana rĊkopisu na postaü drukowaną nie jest tak prosta, jak moĪna byáoby przypuszczaü, wiĊc chylĊ czoáo przed Norą Konopką, Jennifer Ahringer, Glenem Butlerem oraz zespoáem w Taylor & Francis, których bardzo miáo byáo mi poznaü. Za skáad w Cadmus Communications chciaábym podziĊkowaü Eve Malakoff-Klein — Twoja pomoc i praca w czasie caáego procesu produkcji byáa nieoceniona. William Hohl styczeĔ 2009

15 Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

16

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

PodziÚkowania

Informacja o oprogramowaniu Najnowsze oprogramowanie zgodne z kodem prezentowanym w tej ksiąĪce moĪna znaleĨü na stronie http://www.keil.com/demo. DziĊkujĊ!

17 Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

18

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

Informacja o oprogramowaniu

Autor William Hohl pracuje na stanowisku Worldwide University Relations Manager w ARM, w Austin w Teksasie. Pracuje dla ARM od niemal 12 lat, a zacząá od stanowiska gáównego inĪyniera projektu, pomagając przy budowie mikroprocesora ARM1020. Jego odczyty i wykáady, w ramach których czĊsto przedstawiaá temat mikroprocesorów o niskim poborze mocy i programowania w jĊzyku asemblera, miaáy miejsce na uniwersytetach w 36 krajach na piĊciu kontynentach. Oprócz tego, Īe pracowaá jako inĪynier, byá równieĪ w latach 1998 do 2004 adiunktem w Austin, gdzie wykáadaá matematykĊ. Przed zatrudnieniem w ARM pracowaá w Motorola Semiconductor Product Sector (teraz Freescale) w grupie projektowej ColdFire i 68040 oraz w Texas Instruments jako inĪynier aplikacji. Zdobyá tytuáy MSEE oraz BSEE w Texas A&M University oraz szeĞü patentów dotyczących architektur debugowania. JeĪeli nie podróĪuje, moĪna go znaleĨü na jego farmie za Austin w Teksasie.

19 Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

20

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

Autor

Rozdziaï 1

1

PrzeglÈd systemów komputerowych 1.1. WST}P WiĊkszoĞü uĪytkowników telefonów komórkowych nigdy siĊ nie zastanawiaáa, jak wiele pracy wymagaáo zaprojektowanie tego powszechnego obecnie urządzenia. Gdy zajrzymy pod wyĞwietlacz, poniĪej umieszczonego w tle zdjĊcia syna trzymającego balon znajduje siĊ páytka zawierająca ukáady i przewody, algorytmy, które byáy tworzone i udoskonalane przez dekady, oraz oprogramowanie, dziĊki któremu wszystkie te elementy ze sobą wspóápracują. Co rzeczywiĞcie dzieje siĊ w tych ukáadach? Jak one faktycznie dziaáają? RozwaĪmy fikcyjne urządzenie (choü prawdopodobnie znajdziemy podobne na rynku), takie jak przenoĞny tablet wyĞwietlający na bieĪąco obraz telewizyjny, zapewniający nawigacjĊ satelitarną, wykonywanie poáączeĔ telefonicznych, sáuĪący jako komputer osobisty i zawierający niemal wszystkie wykorzystywane interfejsy (np. USB, Wi-Fi, Bluetooth oraz Ethernet), które jest pokazane na rysunku 1.1.

RYSUNEK 1.1. PrzenoĞny komunikator bezprzewodowy

21 Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

22

1

Asembler dla procesorów ARM. PodrÚcznik programisty

Pod ekranem znajduje siĊ páytka drukowana (PCB) z pewną liczbą pojedynczych komponentów elektronicznych oraz co najmniej dwoma ukáadami typu „system w ukáadzie scalonym” (SoC). SoC jest niczym innym jak poáączeniem procesorów, pamiĊci oraz ukáadu graficznego umieszczonych w jednej obudowie, dziĊki czemu oszczĊdzamy miejsce i prąd. JeĪeli przyjrzymy siĊ bliĪej jednemu z takich ukáadów SoC, znajdziemy w nich dwa lub trzy wyspecjalizowane mikroprocesory odpowiedzialne za silnik graficzny, jednostkĊ zmiennoprzecinkową, jednostkĊ zarządzania energią oraz inne urządzenia uĪywane do przenoszenia informacji z jednego urządzenia do innego. Dobrym przykáadem nowoczesnego ukáadu SoC jest TMS320DM355 firmy Texas Instruments pokazany na rysunku 1.2.

RYSUNEK 1.2. TMS320DM355 — SoC firmy Texas Instruments (za pozwoleniem Texas Instruments)

Projekty ukáadów SoC stają siĊ coraz bardziej záoĪone, poniewaĪ inĪynierowie starają siĊ przy ich tworzeniu oszczĊdzaü czas i pieniądze. WyobraĨ sobie, Īe musisz wytworzyü nastĊpną generacjĊ naszego fikcyjnego urządzenia — czy lepiej bĊdzie wykorzystaü czĊĞü wczeĞniejszego projektu, któremu poĞwiĊciliĞmy dziewiĊü miesiĊcy pracy, czy wyrzuciü je i spĊdziü kolejne trzy lata na budowaniu kolejnego, innego ukáadu SoC? PoniewaĪ czas inwestowany w projektowanie nowych produktów skraca siĊ z uwagi na rosnący popyt, áatwo zauwaĪyü trend wykorzystywania istniejących projektów, szczególnie tych, które zostaáy intensywnie przetestowane i są powszechnie uĪywane, do budowania nowych produktów na ich podstawie. Te sprawdzone projekty są przykáadem „wáasnoĞci intelektualnej” — projektów i koncepcji, które mogą byü licencjonowane innym firmom do uĪycia w duĪych projektach. Zamiast projektowaü mikroprocesor od podstaw, firmy wykorzystują znane projekty, na przykáad Cortex-A8 z firmy ARM, i budują na ich podstawie záoĪone systemy. Co wiĊcej, elementy projektu są czĊsto tak pomyĞlane, aby moĪna byáo wykorzystywaü okreĞlone standardy, przez co w przypadku zmiany

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

PrzeglÈd systemów komputerowych

23

jednego komponentu, na przykáad w razie koniecznoĞci uĪycia szybszego procesora, inĪynierowie mogą skorzystaü z wszystkich pozostaáych urządzeĔ (np. dekodera MPEG czy jednostki zmiennoprzecinkowej), w których rozwój równieĪ zainwestowano lata pracy. Wymieniony zostanie wyáącznie mikroprocesor. Pomysá budowania kompletnych systemów wokóá mikroprocesora przyjąá siĊ równieĪ wĞród projektantów mikrokontrolerów. Mikroprocesor moĪe byü uznany za silnik obliczeniowy niemający urządzeĔ peryferyjnych. Bardzo proste procesory mogą byü poáączone z uĪytecznymi dodatkami, takimi jak stopery, uniwersalne nadajniki/odbiorniki asynchroniczne (UART) lub konwertery analogowo-cyfrowe (A/C), tworząc mikrokontroler. Jest to zwykle bardzo tanie urządzenie wykorzystywane w sterownikach przemysáowych, wyĞwietlaczach, zastosowaniach motoryzacyjnych, zabawkach, a takĪe w setkach innych miejsc, w których nie spodziewamy siĊ znaleĨü komputera. PoniewaĪ te zastosowania stają siĊ coraz bardziej wymagające, mikrokontrolery równieĪ stają siĊ coraz bardziej záoĪone, a stosowane dziĞ powszechnie czĊĞci przewyĪszają te, które byáy produkowane nawet niewiele lat wczeĞniej. Ale pomimo tego projekty te nadal realizuje siĊ, pozostawiając caáoĞü systemu bez zmian i wymieniając wyáącznie centralny mikroprocesor.

1.2. HISTORIA ARCHITEKTURY RISC Zanim komputery staáy siĊ tak powszechne jak obecnie, na uczelniach i w biurach znajdowaáy siĊ czĊsto pod schodami lub w piwnicach. Przed powstaniem komputerów osobistych w latach 80. ubiegáego stulecia dominowaáy komputery typu mainframe, takich producentów jak Amdahl, Digital Equipment Corporation (DEC) czy IBM. Wystarczy tylko przespacerowaü siĊ po muzeum, aby zauwaĪyü, jak ogromne byáy to urządzenia. Stosowane w nich architektury procesorów rozwijaáy siĊ dziĊki potrzebie szybszego dziaáania oraz zapewnienia lepszego wsparcia dla záoĪonych systemów operacyjnych. Seria minikomputerów i mainframe DEC VAX byáa dosyü popularna, ale w przeciwieĔstwie do konkurencyjnych architektur IBM System/38, Motorola 68000 czy Intel iAPX-432 ich procesory byáy tak rozbudowane, Īe trudno byáo je efektywnie rozwijaü. Zespoáy inĪynierów spĊdzaáy lata na próbach zwiĊkszenia czĊstotliwoĞci zegara procesora, dodania kolejnych skomplikowanych instrukcji i zwiĊkszenia iloĞci danych, jakich moĪna byáo uĪywaü. Obecnie projektanci realizują te same zadania, ale w wiĊkszoĞci nowoczesnych systemów muszą uwaĪaü na pobieraną moc, co jest szczególnie waĪne w systemach wbudowanych, czĊsto zasilanych jedną baterią. WczeĞniej rozpraszana moc nie stanowiáa problemu — wystarczyáo uĪyü wiĊkszego wentylatora czy nawet wody do odprowadzania nadmiaru ciepáa! Historia komputerów o ograniczonej liczbie rozkazów (RISC) trwa juĪ od dáuĪszego czasu. Pierwsze prace w tym kierunku byáy prowadzone pod koniec lat 60. i na początku 70. ubiegáego stulecia w firmach IBM, Control Data Corporation i Data General. W roku 1981 i 1982 David Patterson oraz Carlo Séquin z University of California, znajdującego siĊ w Berkeley, analizowali moĪliwoĞü zbudowania procesora o mniejszej liczbie instrukcji (Patterson i Sequin 1982; Patterson i Ditzel 1980), podobnie jak John Hennessy ze Standford (Hennessy i in. 1981). Ich celem byáo utworzenie bardzo prostej architektury, która nie wykorzystywaáaby tradycyjnych technik projektowych z komputerów o záoĪonej liczbie rozkazów (CISC), a wiĊc uĪycia mikrokodu (zdefiniowany poniĪej) w procesorze, korzystania z instrukcji o róĪnej dáugoĞci, obsáugi záoĪonych instrukcji wykonywanych w kilku cyklach. Nowe architektury dawaáy w efekcie procesory o nastĊpujących cechach:

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

1

24

1

Asembler dla procesorów ARM. PodrÚcznik programisty

• Wszystkie instrukcje byáy wykonywane w jednym cyklu. Byáo to niezwykáe, poniewaĪ w tym czasie wiele instrukcji procesora byáo wykonywanych w kilku cyklach. DziĊki temu dostĊpne byáy takie instrukcje jak MUL (mnoĪenie), w związku z czym nie trzeba byáo ich budowaü z uĪyciem operacji dodawania i przesuwania, co uáatwiaáo pracĊ programistom. Z kolei znacznie bardziej skomplikowane byáo projektowanie procesora. Instrukcje w komputerach mainframe byáy budowane wewnĊtrznie z operacji prostych, ale niekoniecznie dziaáaáy szybciej od prostszych instrukcji w kodzie. Na przykáad procesor VAX miaá instrukcjĊ INDEX, która dziaáaáa wolniej niĪ fragment programu napisany za pomocą prostszych poleceĔ! • Wszystkie instrukcje miaáy ten sam rozmiar i staáy format. Perfekcyjnym przykáadem procesora CISC jest procesor Motorola 68000, w którym instrukcje mają zmienną dáugoĞü i mogą operowaü na dáugich staáych. Niektóre instrukcje mają 2 bajty, niektóre 4, a czĊĞü jest nawet dáuĪsza. Powodowaáo to, Īe procesorowi trudno byáo dekodowaü przekazane instrukcje i nastĊpnie je wykonywaü. • Instrukcje byáy bardzo proste do zdekodowania. Liczba rejestrów potrzebnych do wykonania operacji w wiĊkszoĞci instrukcji znajduje siĊ w tym samym miejscu. Maáa liczba instrukcji powoduje, Īe do zakodowania operacji potrzeba mniej bitów. • Nie moĪna byáo stosowaü mikrokodu. Jednym z czynników komplikujących projekt procesora jest uĪycie mikrokodu, który stanowi pewnego rodzaju „oprogramowanie” lub polecenia wewnątrz procesora, kontrolujące wewnĊtrzny przepáyw danych. Prosta instrukcja, taka jak MUL (mnoĪenie), moĪe zawieraü kilkanaĞcie wierszy mikrokodu obsáugującego pobieranie danych z rejestrów, przesyáanie tych danych do sumatorów i ukáadów logicznych, a nastĊpnie umieszczenie wyniku w rejestrze procesora lub w pamiĊci. Tego typu projekt pozwala na tworzenie dosyü skomplikowanych instrukcji — na przykáad instrukcja POLY w procesorze VAX wyliczaáa wartoĞü wielomianu n-tego stopnia dla argumentu x na podstawie listy wspóáczynników umieszczonej w pamiĊci oraz wartoĞci n. Choü instrukcja POLY wykonywaáa zadanie wielu instrukcji, w kodzie programu pojawiaáa siĊ jako pojedyncza instrukcja. • Znacznie áatwiej byáo testowaü prostsze ukáady. Z kaĪdą nową generacją procesorów dodawane są nowe funkcje zwiĊkszające wydajnoĞü, ale powoduje to komplikowanie projektu. Architektury CISC staáy siĊ bardzo trudne do testowania i trudno byáo poprawiaü báĊdy, wiĊc producenci musieli byü pewni, Īe sprzedają produkt dziaáający w zdefiniowany sposób. • Dane w pamiĊci zewnĊtrznej byáy dostĊpne poprzez jawnie zdefiniowane instrukcje Load i Store. Wszystkie pozostaáe instrukcje, takie jak dodawanie, odejmowanie czy operacje logiczne, wykorzystują wyáącznie rejestry procesora. RóĪni siĊ to od instrukcji z architektury CISC, gdzie moĪna byáo uĪyü pojedynczej instrukcji pobierającej dane z pamiĊci, wykonującej pewną operacjĊ i zapisującej dane z powrotem w pamiĊci. Ten sposób jest áatwiejszy dla programisty i jest szczególnie uĪyteczny w kompilatorach, ale znacznie trudniejszy do wykorzystania przez projektantów procesora. • WielkoĞü programu zwiĊkszaáa siĊ, poniewaĪ skomplikowane instrukcje w starszych architekturach wymagają uĪycia wiĊkszej liczby instrukcji RISC do zrealizowania tego samego zadania. Na przykáad w symulacjach wykonywanych na maáych programach kod napisany dla pierwszego procesora Berkeley RISC byá okoáo 30% wiĊkszy niĪ analogiczny kod dla VAX 11/780. Nowa architektura RISC bazowaáa na zaáoĪeniu, Īe dziĊki prostszym operacjom moĪna zwiĊkszyü czĊstotliwoĞü zegara procesora, co skompensuje zwiĊkszenie liczby instrukcji.

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

PrzeglÈd systemów komputerowych

25

Po 27 latach te same zasady są stosowane przy projektowaniu wiĊkszoĞci nowoczesnych procesorów. Pomimo zabiegów marketingowych do dziĞ nie przetrwaáo kilka dobrych projektów RISC. Przykáadem moĪe byü procesor Alpha firmy DEC, który w swoim czasie byá uznawany za najlepszy projekt, rodzina 29000 firmy AMD, procesor Motorola 88000, który siĊ nie przyjąá pomimo caákiem zaawansowanego projektu. Znaczenie akronimu RISC równieĪ zmieniáo siĊ w stosunku do jego oryginalnego sensu. Zasada ograniczenia liczby instrukcji przez usuniĊcie najbardziej skomplikowanych przestaáa byü respektowana i pojawiáo siĊ wiele nowych, choü uĪytecznych instrukcji. Wszyscy producenci mikroprocesorów RISC popeánili ten grzech. W kaĪdej nowej generacji procesorów dodawane byáy kolejne instrukcje wspierające wymagające algorytmy stosowane w nowoczesnym sprzĊcie. W przemyĞle jest to nazywane „gadĪeciarstwem”. Wprawdzie wiĊkszoĞü zasad pierwszych procesorów RISC nadal obowiązuje, wystarczy jednak porównaü listĊ instrukcji pierwszego procesora Berkeley RISC-1 (31 instrukcji) lub drugiego procesora ARM (46 instrukcji) z listą instrukcji nowoczesnego ARM (kilkaset), aby samemu dojĞü do wniosku, Īe „R” w skrócie RISC jest juĪ przeszáoĞcią.

1.2.1. POCZkTKI FIRMY ARM Historia firmy ARM Holdings PLC zaczyna siĊ od nieistniejącej juĪ firmy Acorn Computers, która zajmowaáa siĊ przez wiele lat budowaniem komputerów osobistych, przede wszystkim na potrzeby rynku edukacyjnego w Wielkiej Brytanii. NastĊpca popularnego BBC Micro nosiá nazwĊ Acorn Business Computer. Zamiast nadal korzystaü z mikroprocesora 6502, zadecydowano o zaprojektowaniu wáasnego produktu. Steve Furber, który peániá funkcjĊ profesora informatyki w Manchester University, oraz Sophie Wilson, która opracowaáa pierwszy zestaw instrukcji, zaczĊli w paĨdzierniku 1983 roku wspóápracĊ z zespoáem projektowym firmy Acorn, a firma VLSI Technology (wykupiona póĨniej przez Philips Technology) zajĊáa siĊ produkcją pierwszych egzemplarzy. ARM1 wróciá z fabryki 26 kwietnia 1985 roku. Skáadaá siĊ z mniej niĪ 25 000 tranzystorów, co na obecne standardy jest mniejszą liczbą niĪ w dobrym ukáadzie mnoĪącym. Warto wspomnieü, Īe ten ukáad od razu dziaáaá i wykonywaá kod juĪ w dniu, w którym zostaá dostarczony, co przy tak ograniczonym czasie byáo imponujące. PoniewaĪ znamy tempo ewolucji informatyki, warto spojrzeü na inny wskaĨnik — szybkoĞü procesora. Obecne komputery biurowe rutynowo korzystają z zegara 3 – 4 GHz i są produkowane w procesie 45 nm, procesory wbudowane zwykle korzystają z zegara od 50 MHz do 1 GHz, w zaleĪnoĞci od dostĊpnoĞci zasilania. Oryginalny ARM1 byá zaprojektowany do pracy z zegarem 4 MHz (zwróü uwagĊ, Īe jest to o trzy rzĊdy wielkoĞci wolniej) w procesie 3 mikronów! Kolejna wersja architektury zostaáa zastosowana w ARM2 przedstawionym na rysunku 1.3. Choü ten procesor nadal nie miaá pamiĊci podrĊcznej ani jednostki zarządzania pamiĊcią (MMU), w celu zwiĊkszenia wydajnoĞci dodane zostaáy instrukcje mnoĪenia, mnoĪenia i dodawania oraz záącze koprocesora pozwalające na uĪycie zewnĊtrznego akceleratora zmiennoprzecinkowego. Do architektury zostaáy dodane kolejne rejestry, a usuniĊty zostaá jeden z typów adresów efektywnych. Ten mikroprocesor pracowaá z czĊstotliwoĞcią 18 MHz w procesie 2 mikronów. Firma Acorn wykorzystaáa go w nowym komputerze Archimedes, a VLSI sprzedawaáa go (pod nazwą VL86C010) jako czĊĞü zestawu procesora, w który wchodziá kontroler pamiĊci, kontroler wideo oraz kontroler wejĞcia-wyjĞcia.

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

1

26

Asembler dla procesorów ARM. PodrÚcznik programisty

1

RYSUNEK 1.3. Procesor ARM2

1.2.2. POWSTANIE ARM LTD. W roku 1989 w dominujących architekturach procesorów, takich jak rodzina 68000 z firmy Motorola lub x86 z firmy Intel, zacząá siĊ proces integrowania jednostek zarządzania pamiĊcią, pamiĊci podrĊcznej oraz jednostek zmiennoprzecinkowych w procesorze, przy jednoczesnym zwiĊkszaniu czĊstotliwoĞci taktowania — 25 MHz w pierwszym 64040 (jest to nieco mylące, poniewaĪ procesor korzystaá z zegara kwadraturowego, w którym zegar stanowią dwie nakáadające siĊ fazy dwóch przesuniĊtych zegarów, wiĊc wewnĊtrznie pracowaá z dwa razy wiĊkszą czĊstotliwoĞcią). Aby rywalizowaü z tymi produktami, zaprojektowano ARM3 zawierający 4K wbudowanej pamiĊci podrĊcznej, pracujący z czĊstotliwoĞcią 25 MHz. W tych czasach Acorn miaá problemy spowodowane dominacją na rynku IBM PC, ale nadal sprzedawaá swoje wyroby szkoáom, specjalistom i hobbystom. Z kolei firmie VLSI udaáo siĊ znaleĨü inne firmy, które wykorzystywaáy procesory ARM w swoich produktach, szczególnie jako procesor wbudowany, a przypadkiem firma znana ze swoich komputerów osobistych, Apple, chciaáa wejĞü na zupeánie nowy rynek — przenoĞnych asystentów cyfrowych (PDA).

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

PrzeglÈd systemów komputerowych

27

Zainteresowanie Apple’a procesorem dla nowego urządzenia spowodowaáo powstanie zupeánie nowej firmy, która miaáa zająü siĊ jego opracowaniem. Jej udziaáowcami byáy firmy Apple oraz Acorn Group, a dyrektorem zarządzającym zostaá Robin Saxby (obecnie sir Robin Saxby). Nowa firma zatrudniáa czĊĞü inĪynierów z firmy Acorn, którzy brali udziaá w projektowaniu pierwszych procesorów ARM, przeniosáa siĊ do nowego budynku, zmieniáa nazwĊ architektury z Acorn RISC Machine na Advanced RISC Machine i opracowaáa caákowicie nowy model biznesowy. Zamiast sprzedawaü mikroprocesory, Advanced RISC Machines Ltd. zaczĊáa sprzedawaü innym firmom prawa do produkcji procesorów, a w roku 1990 pierwszym licencjobiorcą staáa siĊ VLSI Technology. RozpoczĊáy siĊ prace, które miaáy doprowadziü do powstania projektu dziaáającego w oddzielnym procesorze lub jako makrokomórka w wiĊkszym projekcie, dziĊki czemu licencjobiorca mógáby dodawaü swoją logikĊ do procesora. Po wprowadzeniu rozszerzeĔ do architektury pominiĊto kilka numerów i nazwano ją ARM6 (co byáo wyáącznie zabiegiem marketingowym). Podobnie jak w przypadku konkurencji, procesor ten korzystaá z 32-bitowego adresowania i obsáugiwaá format pamiĊci big endian i little endian. Procesor uĪyty przez Apple’a nosiá nazwĊ ARM610 i skáadaá siĊ z rdzenia ARM6, 4K pamiĊci podrĊcznej, bufora zapisu oraz MMU. Niestety choü Apple PDA (znany jako Newton) wyprzedzaá swój czas, sáabo radziá sobie na rynku, czĊĞciowo z powodu ceny, a czĊĞciowo z powodu wielkoĞci. Dopiero pod koniec lat 90. ubiegáego wieku firma Apple zaprojektowaáa urządzenie, które fundamentalnie zmieniáo spojrzenie ludzi na media cyfrowe — iPoda. Materiaá zaprezentowany w tej ksiąĪce bazuje na procesorze ARM7. Zostaá on wprowadzony na rynek w roku 1993. Projekt zostaá uĪyty przez Acorn w nowej linii komputerów oraz przez firmĊ Psion w nowej linii asystentów PDA. Nadal brakowaáo w nim jednak funkcji, które spowodowaáy olbrzymi sukces jego nastĊpcy — ARM7TDMI pokazanego na rysunku 1.4. Choü trudno sobie obecnie wyobraziü budowanie systemu bez moĪliwoĞci przeglądania rejestrów procesora, systemu pamiĊci, kodu Ĩródáowego C++ oraz stanu procesora w przyjemnym dla oka interfejsie graficznym, to wczeĞniej debugowanie byáo trudnym zadaniem, wymagającym uĪycia duĪej iloĞci dodatkowego sprzĊtu. W ARM7TDMI oryginalny projekt ARM7 zostaá rozbudowany o nowy sprzĊt przeznaczony do obsáugi zewnĊtrznego debugera (litery „D” i „I” oznaczaáy odpowiednio Debug oraz ICE, czyli In-Circuit Emulation), dziĊki czemu budowanie i testowanie kompletnego systemu byáo áatwiejsze i taĔsze. W celu zwiĊkszenia wydajnoĞci w procesorach wbudowanych zaprojektowano nowy, skompresowany zestaw instrukcji. Nosiá on nazwĊ THUMB i pozwalaá projektantom oprogramowania na wybór miĊdzy umieszczeniem wiĊkszej iloĞci kodu w tej samej iloĞci pamiĊci a zmniejszeniem iloĞci pamiĊci w danym projekcie. Rosnący przemysá telefonii komórkowej entuzjastycznie przyjąá nową funkcjĊ i w konsekwencji projekt ARM7TDMI byá powszechnie adaptowany w telefonach komórkowych. Początkowe „M” oznaczaáo wiĊkszy sprzĊtowy ukáad mnoĪący, dziĊki czemu procesor lepiej nadawaá siĊ do algorytmów DSP. Poáączenie niewielkiej powierzchni ukáadu z niskim zuĪyciem energii oraz bogatą listą instrukcji spowodowaáo, Īe ARM7TDMI staá siĊ najlepiej sprzedającym siĊ procesorem ARM i pomimo swojego wieku nadal jest uĪywany w nowoczesnych systemach wbudowanych. Wszystkie te funkcje byáy uĪywane i usprawniane w kolejnych projektach. W latach 90. ubiegáego wieku ARM wprowadzaá kolejne usprawnienia do architektury, udostĊpniając kolejno rdzenie procesorów ARM8, ARM9 i ARM10, jak równieĪ ich pochodne. Choü warto byáoby opisaü te projekty, to mogáoby to byü tematem kolejnej ksiąĪki. Przedstawimy tylko kilka faktów z tej dekady. W czasie gdy powstawaá ARM9, zawarto z firmą Digital Equipment Corporation umowĊ pozwalającą jej tworzyü wáasną wersjĊ architektury ARM, nazwaną StrongARM, której druga wersja zostaáa wysáana do produkcji w tym samym czasie

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

1

28

Asembler dla procesorów ARM. PodrÚcznik programisty

1

RYSUNEK 1.4. ARM7TDMI

co ARM10. Ostatecznie DEC sprzedaá swoją grupĊ projektową firmie Intel, gdzie zdecydowano o kontynuowaniu prac pod wáasną marką XScale. Intel wyprodukowaá drugą wersjĊ swojego projektu, a nastĊpnie sprzedaá go firmie Marvell. I na koniec notka z rynku korporacyjnego: w roku 1998 firma ARM Holdings PLC zadebiutowaáa na gieádzie w Londynie i Nowym Jorku jako spóáka publiczna. Na początku nowego stulecia ARM wyprodukowaá kilka nowych linii procesorów, w tym rodziny ARM11, Cortex oraz procesory do urządzeĔ wspierających bezpieczeĔstwo oraz do zastosowaĔ wielordzeniowych. Warto wiedzieü, Īe wszystkie te procesory z programistycznego punktu widzenia róĪniáy siĊ wersją. Na podstawie rysunku 1.5 moĪna zauwaĪyü, Īe choü dostĊpnych byáo wiele róĪnych rdzeni ARM, to wersja precyzyjnie okreĞlaáa zbiór instrukcji dostĊpnych w kaĪdym z nich. Pozostaáe waĪne funkcje, takie jak architektura pamiĊci, wsparcie dla Ğrodowiska Java i obsáuga operacji zmiennoprzecinkowych, są realizowane w róĪnych rdzeniach. Na przykáad ARM1136JF-S jest záoĪonym procesorem, obsáugującym sprzĊtowo operacje zmiennoprzecinkowe oraz Ğrodowisko Java, ale obsáuguje zbiór instrukcji w wersji 6, wiĊc pomimo implementacji bazującej na ARM11 architektura zbioru instrukcji (ISA) dyktuje, których instrukcji moĪe uĪywaü kompilator. W tej ksiąĪce skupimy siĊ na zbiorze instrukcji ARM Version 4T, ale w razie potrzeby moĪna áatwo nauczyü siĊ kolejnych zbiorów.

1.2.3. ARM OBECNIE Do roku 2002 powstaáo okoáo 1,3 miliarda urządzeĔ bazujących na procesorach ARM, zastosowanych w wielu róĪnych produktach, przewaĪnie w telefonach komórkowych. Do tego czasu firma Nokia byáa dominującym graczem na rynku telefonii komórkowej i to wáaĞnie procesory ARM zostaáy zastosowane w jej urządzeniach. Choü TI dostarczaá duĪą czĊĞü ukáadów producentom telefonów komórkowych, to pozostali partnerzy ARM, w tym Philips, Analog Devices, LSI Logic, PraireComm, Intel i Qualcomm, równieĪ mieli swój udziaá, przede wszystkim oferując procesor ARM7 (poza platformą OMAP firmy TI, która bazowaáa na ARM9).

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

PrzeglÈd systemów komputerowych

29

1

RYSUNEK 1.5. Wersje architektury

Ukáady zintegrowane specyficzne dla zastosowania (ASIC) wymagaáy uĪycia nie tylko rdzenia procesora — potrzebne byáy równieĪ ukáady peryferyjne, takie jak zegary, interfejsy USB, standardowe biblioteki komórek, silniki graficzne, DSP oraz magistrale spinające razem te elementy. Aby wyjĞü poza projektowanie procesorów, ARM zacząá kupowaü inne firmy specjalizujące siĊ w wymienionych obszarach. W roku 2003 ARM kupiá Adelante Technologies dla jej silników danych (procesory DSP). W roku 2004 zakupiá Axys Design Automation w celu zapewnienia nowych narzĊdzi sprzĊtowych oraz Artisan Components z uwagi na jej standardowe biblioteki komórek i kompilatory pamiĊci. W roku 2005 zostaáa zakupiona firma Keil Software oferująca narzĊdzia dla mikrokontrolerów. W roku 2006 ARM kupiá Falanx dla akceleratorów grafiki 3D oraz SOISIC w celu pozyskania technologii krzem-na-izolatorze. Przez te szeĞü lat firma ARM znacznie siĊ rozrosáa. Ostatecznym celem byáo zbudowanie caáej architektury „system w ukáadzie” za pomocą technologii ARM. W czasie pisania tej ksiąĪki ponad 10 miliardów procesorów ARM zostaáo wyprodukowanych dla róĪnorodnych urządzeĔ, od aparatów cyfrowych po samochodowe ukáady ABS. WiĊkszoĞü konsumentów prawdopodobnie nie zdaje sobie sprawy, Īe wiele urządzeĔ z ich domów zawiera ukáady ARM, poniewaĪ podobnie jak dostawcy ukáadów scalonych, nie są oni szczególnie doceniani przy okazji prezentacji gotowego produktu. Maáo prawdopodobne jest, Īe uĪytkownik telefonu marki Nokia doceni fakt, Īe ukáady scalone zostaáy wyprodukowane przez TI, a czĊĞü projektu powstaáa w firmie ARM.

1.3. URZkDZENIA LICZkCE Zanim zaczniemy mówiü o procesorach, programach i bitach, warto przytoczyü kilka definicji. Na najbardziej podstawowym poziomie moĪemy mówiü o urządzeniach, które mają zdefiniowany zbiór poleceĔ lub instrukcji dostĊpnych poprzez dowolne mechanizmy — taĞmy papierowe, przeáączniki lub materiaáy magnetyczne. Urządzenie takie nie musi byü elektroniczne. Na przykáad w roku 1804 Joseph Marie Jacquard opracowaá sposób tworzenia wzorów w tkaninie poprzez kontrolowanie przepáywu wątków jedwabiu za pomocą kart z wytáoczonymi w nich otworami. Te same karty zostaáy zmodyfikowane (patrz rysunek 1.6) i uĪyte do przekazywania instrukcji do komputerów w latach od 1960 do 1980. W procesie pisania programów zuĪywano

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

30

1

Asembler dla procesorów ARM. PodrÚcznik programisty

caáe pudáa tych kart, które byáy nastĊpnie przekazywane osobie obsáugującej czytnik kart. Biada temu, kto poĞwiĊciá kilka dni na zapisanie programu na kartach i ich nie ponumerowaá — upuszczenie pudeáka z niemal identycznymi kartami powodowaáo, Īe nieszczĊĞnik musiaá od początku dziurkowaü nowy zestaw kart! Jednak skoro maszyna odczytaáa instrukcje, przed wykonaniem obliczeĔ musiaáy one byü gdzieĞ zapisane. W przeciwnym razie uĪytkownik musiaá ponownie áadowaü instrukcje za kaĪdą iteracją programu. Komputer przechowujący program pobieraá sekwencjĊ instrukcji z pamiĊci wraz z danymi wykorzystywanymi do wykonania obliczeĔ. W tych komputerach znajdowaáo siĊ niewiele komponentów: procesor (który wykonywaá obliczenia), pamiĊü (do przechowywania instrukcji i danych) oraz magistrale do przesyáania programu i danych pomiĊdzy tymi dwoma komponentami, jak jest to pokazane na rysunku 1.7. Tematem tej ksiąĪki są wáaĞnie te instrukcje — programowanie z uĪyciem asemblera polega na wykorzystywaniu podstawowych operacji dostĊpnych w procesorze, zapisanych w taki sposób, aby ludzie mogli je áatwo odczytaü.

RYSUNEK 1.6. Karty Holleritha

RYSUNEK 1.7. Model komputera z pamiĊcią programu

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

PrzeglÈd systemów komputerowych

31

Klasyczny model komputera zawiera równieĪ interfejsy urządzeĔ wejĞcia-wyjĞcia (I/O), takich jak klawiatura, napĊd dyskowy i drukarka. Interfejsy te pozwalają na poáączenie zarówno z procesorem, jak i z pamiĊcią. Trzeba pamiĊtaü, Īe systemy wbudowane mogą nie mieü tych komponentów. WeĨmy pod uwagĊ na przykáad takie urządzenie jak kontroler samochodowego systemu zapobiegającego blokadzie hamowanych kóá (ABS), który jest systemem komputerowym, ale nie ma Īadnego interfejsu do komunikacji z czáowiekiem. Wszystkie dane wejĞciowe pochodzą z czujników podáączonych bezpoĞrednio do ukáadu i nie ma potrzeby wysyáania informacji na wyĞwietlacz czy do drukarki.

1.4. SYSTEMY LICZBOWE PoniewaĪ komputery operują na tranzystorach pracujących jako przeáączniki, ukáady logiczne uĪywane do budowania sumatorów, mnoĪników, dzielników itd. rozumieją wartoĞci 0 i 1, czyli wáączony i wyáączony. Dlatego w systemach komputerowych znacznie áatwiej jest posáugiwaü siĊ systemem binarnym niĪ systemem dziesiĊtnym. W systemie binarnym wykorzystuje siĊ zasadĊ, Īe kaĪda cyfra reprezentuje potĊgĊ dwójki zamiast potĊgi dziesiĊciu. Przy podstawie dziesiĊtnej dostĊpne są cyfry od 0 do 9, wiĊc jeĪeli chciaábyĞ policzyü owce w zagrodzie, moĪesz powiedzieü 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 i braknie Ci cyfr. Dlatego w celu kontynuowania obliczeĔ umieszczamy 1 na pozycji 10 (patrz rysunek 1.8) dla wskazania, Īe policzyliĞmy juĪ do tej liczby, i zaczynamy ponownie uĪywaü cyfr od początku — 10, 11, 12, 13 itd.

RYSUNEK 1.8. Reprezentacja 438 w systemie dziesiĊtnym

Teraz wyobraĨ sobie, Īe masz tylko dwie cyfry, za pomocą których moĪesz liczyü: 0 i 1. Aby zliczyü to samo stado owiec, moĪemy powiedzieü 0, 1 i braknie nam cyfr. Wiemy, Īe nastĊpną wartoĞcią jest 2 przy podstawie 10, ale przy podstawie 2 umieszczamy 1 na drugiej pozycji i zaczynamy liczyü ponownie — 10, 11 i znów brakuje nam cyfr. Ustawiamy wiĊc znacznik na pozycji 4 i zaczynamy od nowa. Przykïad 1.1. Skonwertuj liczbÚ binarnÈ 1101012 na dziesiÚtnÈ.

RozwiÈzanie TÚ liczbÚ moĝna przedstawiÊ w nastÚpujÈcy sposób: 25 1

24 1

23 0

22 1

21 0

20 1

Jest to odpowiednik 32+16+4+1 = 5310 Zazwyczaj indeks jest uĝywany w przypadku stosowania podstawy innej niĝ 10. Interpretacja liczby takiej jak 101 zwykle nie pozostawia ĝadnych wÈtpliwoĂci do momentu, gdy

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

1

32

1

Asembler dla procesorów ARM. PodrÚcznik programisty zaczniemy korzystaÊ z komputerów. Na pierwszy rzut oka 101 zostanie zinterpretowane jako liczba o podstawie 10 — sto jeden. Jednak gdy notacja nie jest stosowana konsekwentnie, moĝemy zinterpretowaÊ ten zapis jako liczbÚ w systemie o podstawie 2, wiÚc przy zapisie liczb o róĝnych podstawach naleĝy zachowaÊ ostroĝnoĂÊ.

Gdyby programiĞci przez caáe dnie gapili siĊ na zera i jedynki, prawdopodobnie mieliby ochotĊ wyskoczyü przez okno, wiĊc lepszym rozwiązaniem jest reprezentowanie liczb w systemie o podstawie 8 (ósemkowym, choü trudno obecnie znaleĨü komputer korzystający z tych liczb) lub 16 (szesnastkowym czy heksadecymalnym; to preferowany wybór), w którym liczby zapisujemy, korzystając z potĊg 16. Tak zapisane liczby nieĨle siĊ pakują i są zaskakująco duĪe po konwersji na system dziesiĊtny. PoniewaĪ liczby o podstawie 10 mają cyfry od 0 do 9 pozwalające na pokazanie liczby jedynek, dziesiątek, setek itd., nie wystarczają one do przedstawienia liczby jedynek przy podstawie 16. Inaczej mówiąc, aby liczyü owce, uĪywając podstawy 16, moĪemy wykorzystaü cyfry 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ale nastĊpnie musimy siĊgnąü po pierwsze szeĞü liter alfabetu. Po cyfrze 9 moĪemy kontynuowaü liczenie — A, B, C, D, E i F. Gdy osiągniemy F, nastĊpną liczbą bĊdzie 1016. Przykïad 1.2. OkreĂl dziesiÚtny odpowiednik liczby A5E916.

RozwiÈzanie Ta liczba szesnastkowa moĝe byÊ przedstawiona jako: 163 A

162 5

161 E

160 9

Liczba pokazana powyĝej to (10×163)+(5×162)+(14×161)+(9×160) = 42 47310. ZwróÊ uwagÚ, ĝe przy wykonywaniu konwersji ïatwiej jest traktowaÊ wartoĂci A, B, C, D, E i F jako liczby o podstawie 10.

Przykïad 1.3. OkreĂl reprezentacjÚ szesnastkowÈ liczby 86210.

RozwiÈzanie ChoÊ obecnie niemal wszystkie kalkulatory majÈ funkcjÚ konwersji, waĝne jest, abyĂ umiaï wykonaÊ to Êwiczenie rÚcznie (jest to czÚste zadanie programistyczne). DostÚpne sÈ tabele pomocnicze, ale najïatwiejszym sposobem jest obliczenie, ile razy dana potÚga szesnastu mieĂci siÚ w naszej liczbie. Nasza liczba jest mniejsza niĝ 163, poniewaĝ 163 wynosi 4096. Dlatego nastÚpnÈ wartoĂciÈ do sprawdzenia jest 162, czyli 256, która mieĂci siÚ trzy razy w naszej liczbie. 862/256 = 3,3672 Po wykonaniu odejmowania zostaje nam: 862–(3×256) = 94

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

PrzeglÈd systemów komputerowych

33

NastÚpnÈ potÚgÈ jest 161, która to wartoĂÊ mieĂci siÚ w 94 piÚÊ razy, pozostawiajÈc 14. Dlatego nasza wartoĂÊ szesnastkowa wynosi: 163

162 3

161 5

160 E

Dobrze wiedzieü, Īe konwersja pomiĊdzy liczbą binarną a szesnastkową jest bardzo prosta — wystarczy pogrupowaü czwórkami cyfry binarne, nazywane bitami, i skonwertowaü te cztery cyfry na odpowiednik szesnastkowy. W tabeli 1.1 pokazane są wartoĞci binarne i szesnastkowe liczb od 0 do 15. TABELA 1.1. Odpowiedniki binarne i szesnastkowe WartoĂÊ dziesiÚtna

WartoĂÊ binarna

WartoĂÊ szesnastkowa

0

0000

0

1

0001

1

2

0010

2

3

0011

3

4

0100

4

5

0101

5

6

0110

6

7

0111

7

8

1000

8

9

1001

9

10

1010

A

11

1011

B

12

1100

C

13

1101

D

14

1110

E

15

1111

F

Przykïad 1.4. Skonwertuj poniĝszÈ liczbÚ binarnÈ na szesnastkowÈ: 110111110000101011112

RozwiÈzanie ZaczynajÈc od bitu najmniej znaczÈcego (po prawej stronie), pogrupuj bity po cztery. PierwszÈ cyfrÈ bÚdzie F16, jak jest to pokazane poniĝej: 110111110000101011112 F16 DrugÈ grupÈ czterech bitów bÚdzie 10102, czyli A16, i tak dalej, co daje nam ostatecznie:

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

1

34

Asembler dla procesorów ARM. PodrÚcznik programisty DF0AF16

1

Jeszcze komentarz na temat notacji — moĝesz spotkaÊ siÚ z liczbami szesnastkowymi zapisanymi jako 0xFFEE lub &FFEE (zaleĝnie od uĝywanych narzÚdzi programistycznych) i liczbami binarnymi zapisanymi jako 2_1101 lub b1101.

1.5. REPREZENTACJA LICZB I ZNAKÓW Dla komputera wszystkie liczby i znaki są po prostu ciągami bitów. Niestety wewnątrz mikroprocesorów nie ma jednostki interpretującej zamierzenia programistów, co mogáoby zaoszczĊdziü niezliczone godziny debugowania i miliardy záotych wydawane na osprzĊt. ProgramiĞci mają juĪ na swoim koncie utracone sondy kosmiczne, poniewaĪ procesory wykonują dokáadnie to, co oprogramowanie kaĪe im robiü. Gdy powiesz 0x6E, komputer widzi 0x6E, kropka. MoĪe to byü znak (maáe „n”), liczba dziesiĊtna 110, a nawet wartoĞü uáamkowa! BĊdziemy do tego wielokrotnie wracaü — komputery muszą „wiedzieü”, w jaki sposób traktowaü te wszystkie typy danych. To programista jest odpowiedzialny za interpretacjĊ wyników dostarczanych przez procesor i jasne zapisanie tego w kodzie. W nastĊpnych trzech punktach przedstawimy sposób zapisu liczb caákowitych, liczb zmiennoprzecinkowych i znaków, a inną metodĊ zapisu uáamków zaprezentujemy w rozdziale 7.

1.5.1. REPREZENTACJA LICZB CA’KOWITYCH Dla podstawowych operacji matematycznych waĪna jest nie tylko odpowiednia reprezentacja liczb, ale równieĪ uĪycie moĪliwie niewielu bitów, poniewaĪ pamiĊü nie moĪe byü marnowana na przechowywanie nadmiarowych lub niepotrzebnych bitów. Liczby caákowite są czĊsto reprezentowane za pomocą bajtów (8 bitów), poáówek sáowa (16 bitów) i sáów (32 bity). Mogą byü nawet dáuĪsze w zaleĪnoĞci od zastosowaĔ, np. procedury kryptograficzne mogą wymagaü liczb 128-bitowych. W reprezentacji bez znaku zakáada siĊ, Īe najbardziej znaczący bit jest uwzglĊdniany przy okreĞlaniu wartoĞci liczby. Na przykáad jeĪeli liczba szesnastkowa 0xFE000004 byáaby przechowywana w rejestrze lub pamiĊci i traktowana jako liczba bez znaku, to ma ona wartoĞü dziesiĊtną: (15×167)+(14×166)+(4×160) = 4 261 412 868 W reprezentacji ze znakiem zakáada siĊ, Īe najbardziej znaczący bit w liczbie jest uĪywany do utworzenia wartoĞci dodatnich lub ujemnych i wystĊpują trzy rodzaje tej reprezentacji: znak-moduá, dopeánienie do jedynki i dopeánienie do dwójki. Zapis znak-moduá jest najáatwiejszy do zrozumienia: najbardziej znaczący bit reprezentuje znak, a pozostaáe bity reprezentują moduá liczby. Jedynka na pozycji znaku informuje, Īe liczba jest ujemna, natomiast zero oznacza, Īe liczba jest dodatnia. Przykïad 1.5. Liczby –18 i 25 sÈ reprezentowane na 16 bitach jako: –18 = 1000000000010010 25 = 0000000000011001

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

PrzeglÈd systemów komputerowych

35

Aby dodaÊ te dwie liczby, na poczÈtku naleĝy sprawdziÊ, która liczba ma wiÚkszy moduï, a nastÚpnie odjÈÊ od niej mniejszy moduï. Znak zostanie pobrany z wiÚkszej liczby, co w tym przypadku oznacza, ĝe bÚdzie miaï wartoĂÊ 0. Na szczÚĂcie reprezentacja znak-moduï nie jest zbyt czÚsto wykorzystywana, poniewaĝ w jej przypadku wymagane jest wczeĂniejsze wykonanie porównania, co wymusza doïÈczenie do kodu dodatkowych instrukcji potrzebnych do przeprowadzenia podstawowych operacji matematycznych.

Liczby z dopeánieniem do jedynki równieĪ nie są wykorzystywane w nowoczesnych systemach komputerowych, gáównie z powodu koniecznoĞci wykonania zbyt wielu dodatkowych operacji przy prostych dziaáaniach matematycznych. Aby w tej reprezentacji utworzyü wartoĞü ujemną, naleĪy odwróciü wszystkie bity dodatniej wartoĞci. Bit znaku bĊdzie miaá wartoĞü 1, tak jak w reprezentacji znak-moduá, ale przy pracy na tych liczbach wystĊpują dwa problemy. Po pierwsze, mamy dwie reprezentacje zera, a po drugie, moĪe byü niezbĊdne korygowanie sumy przy dodawaniu dwóch wartoĞci, co wymaga dodatkowych dziaáaĔ procesora. Przeanalizujmy dwa przykáady. Przykïad 1.6. Przy zaïoĝeniu, ĝe mamy 16-bitowÈ reprezentacjÚ liczby, dodaj wartoĂÊ –124 do 236, korzystajÈc z notacji z dopeïnieniem do jedynki.

RozwiÈzanie Aby utworzyÊ –124 w dopeïnieniu do jedynki, zapiszemy binarnÈ reprezentacjÚ 124 i odwrócimy wszystkie liczby: 124 –124

0000000001111100 1111111110000011

Dodanie 236 daje nam: 124 1111111110000011 + 236 +0000000011101100 ---------------------przeniesienie o 1 0000000001101111

Niestety problemem jest, ĝe wynik wynosi 112 lub 0x70 szesnastkowo. W przypadku uĝycia notacji z dopeïnieniem do jedynki wystÈpienie przeniesienia wymusza dodanie do wyniku jedynki, co jest dodatkowym krokiem: + 1 ----112

0000000001101111 + 1 ----------------0000000001110000

Przykïad 1.7. Dodaj do siebie wartoĂci –8 i 8 przy uĝyciu reprezentacji z dopeïnieniem do jedynki, zakïadajÈc dostÚpnoĂÊ 8 bitów.

RozwiÈzanie Na poczÈtek zapisujemy reprezentacjÚ binarnÈ wartoĂci dodatniej i odwracamy wszystkie bity, uzyskujÈc –8:

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

1

36

Asembler dla procesorów ARM. PodrÚcznik programisty 8 + –8 --0

1

00001000 11110111 -------11111111

Poniewaĝ nie ma przeniesienia z najbardziej znaczÈcego bitu, oznacza to, ĝe 00000000 i 11111111 reprezentujÈ wartoĂÊ zero. WartoĂci +0 i –0 oznaczajÈ wiÚcej pracy dla oprogramowania, szczególnie gdy sprawdzamy, czy wartoĂÊ jest równa zero i prowadzi do uĝycia obu równolegïych reprezentacji w celu unikniÚcia caïego problemu.

Reprezentacja z dopeánieniem do dwójki jest prostsza w uĪyciu, ale wymaga prawidáowej interpretacji. Podobnie jak w przypadku pozostaáych dwóch reprezentacji liczby ze znakiem, najbardziej znaczący bit jest bitem znaku. Jednak w przypadku tej reprezentacji najbardziej znaczący bit jest waĪony, co oznacza, Īe ma taką samą wartoĞü jak w reprezentacji bez znaku. Na przykáad jeĪeli mamy 8-bitową reprezentacjĊ liczby bez znaku, to najbardziej znaczący bit bĊdzie miaá wartoĞü 27, czyli 128. JeĪeli mamy 8 bitów do reprezentacji liczby z dopeánieniem do dwójki, to najbardziej znaczący bit oznacza wartoĞü –128. DziesiĊtna liczba n jest reprezentowana jako m-bitowa liczba binarna z dopeánieniem do dwójki, gdzie b jest wartoĞcią poszczególnych bitów, jako: n

m 2

bm1 2 m1  ¦ bi 2i i 0

Aby moĪna byáo to implementowaü proĞciej, najbardziej znaczący bit moĪe byü uznawany za jedyny ujemny komponent liczby, a wszystkie pozostaáe bity stanowią komponent dodatni. Na przykáad –114 reprezentowane jako liczba 8-bitowa z dopeánieniem do dwójki to: 100011102 = –27+23+22+21 = –114 Zwróü uwagĊ, Īe w powyĪszych obliczeniach jedyną wartoĞcią ujemną jest najbardziej znaczący bit. Nie wolno popeániü pomyáki — musisz wiedzieü wczeĞniej, Īe ta liczba jest traktowana jako liczba z uzupeánieniem do dwójki. W przeciwnym razie moĪe to byü dziesiĊtna liczba 142. Reprezentacja z dopeánieniem do dwójki ma wiele zalet i wad dla okreĞlonych zestawów bitów, na przykáad liczba 8 nie moĪe byü reprezentowana za pomocą 4 bitów, poniewaĪ w 10002 ustawiony jest najbardziej znaczący bit i wartoĞü jest interpretowana jako ujemna (w tym przypadku –8). W tabeli 1.2 są wymienione zakresy wartoĞci zapewnianych dla róĪnych dáugoĞci bitów z wykorzystaniem definicji ARM dla póásáów, sáów oraz podwójnych sáów. Przykïad 1.8. Skonwertuj –9 na reprezentacjÚ z uzupeïnieniem do dwójki na 8 bitach.

RozwiÈzanie Poniewaĝ 9 to 10012, bitowÈ reprezentacjÈ –9 bÚdzie: 00001001 11110110 + 1 -------------11110111

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

9 –9 w dopeđnieniu do 1 –9 w dopeđnieniu do 2

PrzeglÈd systemów komputerowych

37

TABELA 1.2. Zakresy liczb z dopeánieniem do dwójki DïugoĂÊ

Liczba bitów

1

Zakres m–1

m–1

m

–2

8

–128 do 127

Póïsïowo

16

–32 768 do 32 767

Sïowo

32

–2 147 483 648 do 2 147 483 647

Podwójne sïowo

64

–2

Bajt

64

do 2

–1

64

do 2 –1

Uwaga: Aby obliczyü reprezentacjĊ liczby ujemnej z dopeánieniem do dwójki, weĨ jej moduá, skonwertuj na postaü binarną, odwróü wszystkie bity i dodaj 1

Operacje arytmetyczne przebiegajÈ teraz w oczekiwany sposób bez koniecznoĂci korygowania wartoĂci koñcowych. Aby skonwertowaÊ liczbÚ zapisanÈ z uzupeïnieniem do dwójki na liczbÚ dziesiÚtnÈ, moĝesz odjÈÊ jedynkÚ i odwróciÊ wszystkie bity, co jest najszybszym sposobem, albo potraktowaÊ jÈ jako sumÚ –27 i pozostaïych bitów, na przykïad: –27+26+25+24+22+21+20 = –128+119 = –9

Przykïad 1.9. Dodaj wartoĂÊ –384 do 2903, korzystajÈc z 16-bitowych liczb z dopeïnieniem do dwójki.

RozwiÈzanie Na poczÈtek skonwertuj obie wartoĂci na ich reprezentacje z dopeïnieniem do dwójki: 384 = 00000001100000002 –384 = 11111110011111112

+ 1 =

+ 2903 = -----2519

11111110100000002 + 00001011010101112 ---------------00001001110101112

1.5.2. REPREZENTACJA ZMIENNOPRZECINKOWA W wielu aplikacjach mogą byü potrzebne wartoĞci wiĊksze od 2 147 483 647, ale do reprezentowania liczb mamy tylko 32 bity. Bardzo duĪe i bardzo maáe wartoĞci mogą byü konstruowane za pomocą reprezentacji zmiennoprzecinkowej. Choü sam format ma dáugą historiĊ i byá w komputerach przez lata stosowany w wielu odmianach, to ostatecznie w roku 1985 powstaáa specyfikacja IEEE 754 (Standards Comittee 1985), formalnie definiująca 32-bitowy typ danych o pojedynczej precyzji. Te liczby zmiennoprzecinkowe skáadają siĊ z wykáadnika, mantysy, bitu znaku oraz nadmiaru. Dla „normalnych” liczb, a tutaj „normalnoĞü” jest zdefiniowana w specyfikacji, wartoĞü liczby o pojedynczej precyzji F jest wyznaczana jako: F = –1s×1.f×2e–b

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

38

1

Asembler dla procesorów ARM. PodrÚcznik programisty

gdzie s jest bitem znaku, a f jest mantysą skáadającą siĊ z niĪszych 23 bitów formatu. Najbardziej znaczący bit mantysy ma wartoĞü 0,5, nastĊpny ma wartoĞü 0,25 i tak dalej. Aby wszystkie wykáadniki miaáy wartoĞü dodatnią, do wykáadnika e jest dodawany bit nadmiaru b. Dla liczb o pojedynczej precyzji nadmiarem wykáadnika jest –127. Choü zakres 32-bitowej liczby caákowitej bez znaku wynosi od 0 do 232–1 (4,3×109), to zakres dodatnich wartoĞci liczby zmiennoprzecinkowej o pojedynczej precyzji, równieĪ reprezentowanych na 32 bitach, wynosi od 1,2×10–38 do 3,4×10+38! Zwróü uwagĊ, Īe jest to tylko zakres liczb dodatnich, zakres liczb ujemnych jest analogiczny. Oczywiste jest, Īe niezwykáy zakres pociąga za sobą pewne wady. W liczbach zmiennoprzecinkowych poĞwiĊcamy dokáadnoĞü w zamian za zakres, poniewaĪ odlegáoĞci pomiĊdzy reprezentowanymi liczbami zwiĊkszają siĊ wraz ze wzrostem wartoĞci wykáadnika. Formaty caákowite mają staáą dokáadnoĞü. Przykïad 1.10. Zapisz liczbÚ 1,5 w formacie zmiennoprzecinkowym o pojedynczej precyzji. WartoĂÊ ta bÚdzie siÚ skïadaÊ z: s = 0 (liczba dodatnia) f = 100 0000 0000 0000 0000 0000 (23 bity mantysy reprezentujÈce 0,5) e = 0+127 (8 bitów wykïadnika plus nadmiar) F = 0 0111111 100 0000 0000 0000 0000 0000 lub 0x3FC00000, jak jest to pokazane na rysunku 1.9.

RYSUNEK 1.9. Zapis liczby 1,5 w formacie o pojedynczej precyzji

DuĪy dynamiczny zakres reprezentacji zmiennoprzecinkowej spowodowaá, Īe jest popularna w oprogramowaniu naukowym i inĪynierskim. Choü pokazaliĞmy tylko format o pojedynczej precyzji, to standard IEEE 754 definiuje równieĪ 64-bitowy format, który ma zakres od ±2,2×10–308 do 1,8×10+308! W tabeli 1.3 jest pokazane, jak wyglądają dwa najczĊĞciej uĪywane formaty standardu IEEE (pojedyncza i podwójna precyzja). Pojedyncza precyzja zapewnia 6 – 9 cyfr precyzji, natomiast podwójna precyzja daje nam 15 – 17 cyfr. TABELA 1.3. Formaty IEEE 754 o pojedynczej i podwójnej precyzji Format SzerokoĂÊ formatu w bitach SzerokoĂÊ wykïadnika w bitach Bity mantysy

Pojedyncza precyzja

Podwójna precyzja

32

64

8

11

23

52

+127

+1023

Minimalny wykïadnik

–126

–1022

Nadmiar wykïadnika

127

1023

Maksymalny wykïadnik

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

PrzeglÈd systemów komputerowych

39

Do obsáugi liczb w tych formatach wymagany jest specjalny sprzĊt. Historycznie jednostki zmiennoprzecinkowe byáy osobnymi ukáadami scalonymi podáączanymi do gáównego procesora, np. Intel 80387 dla 80386 czy Motorola 68881 dla 68000. NastĊpnie byáy integrowane na tym samym kawaáku krzemu, ale byáy dostĊpne za dodatkową opáatą. Jednostki zmiennoprzecinkowe są czĊsto duĪe, zwykle o wielkoĞci podobnej do procesora bez pamiĊci podrĊcznej. W wiĊkszoĞci zastosowaĔ obliczenia zmiennoprzecinkowe są rzadkie i nie są krytyczne czasowo. Z tych powodów wiĊkszoĞü mikrokontrolerów nie zawiera wyspecjalizowanego ukáadu zmiennoprzecinkowego, a zamiast tego korzysta albo z procedur programowych do emulowania operacji zmiennoprzecinkowych, albo z wolniejszych metod caákowitych. Istnieje równieĪ inny format, który moĪe byü uĪywany przy pracy na wartoĞciach dziesiĊtnych o staáej liczbie cyfr znaczących. Nie wymaga on specjalnego sprzĊtu do implementacji. Formaty o staáej liczbie cyfr znaczących bĊdą opisane dokáadniej w rozdziale 7.

1.5.3. REPREZENTACJA ZNAKOWA Wzorce bitowe mogą reprezentowaü liczby lub znaki, a ich reprezentacja jest zawsze zaleĪna od kontekstu. Na przykáad wzorzec bitowy 01000001 moĪe byü liczbą 65 w procedurze kodowania dĨwiĊku albo literą „A”. To program decyduje, w jaki sposób wzorzec ten jest uĪywany i interpretowany. Na szczĊĞcie juĪ dawno temu zostaáy opracowane standardy kodowania danych znakowych, na przykáad American Standard Code for Information Interchange lub ASCII, w którym kaĪda litera lub znak sterujący ma przypisaną wartoĞü binarną. Innymi standardami są Extended Binary-Coded-Decimal Interchange Code (EBCDIC) oraz Baudot, ale obecnie najczĊĞciej uĪywany jest ASCII. Tablica znaków ASCII jest zamieszczona w dodatku C. Choü obecnie wiĊkszoĞü urządzeĔ moĪe potrzebowaü tylko podstawowych znaków, takich jak litery, cyfry i znaki przestankowe, to w kodzie ASCII zdefiniowane są równieĪ znaki sterujące, które mogą byü interpretowane przez urządzenie. Na przykáad stare dalekopisy miaáy dzwonek, który pozwalaá informowaü operatora o nadchodzącym interesującym zdarzeniu. Znakiem sterującym powodującym uruchomienie dzwonka jest 0x07. Innymi znakami sterującymi są: znak cofacza (0x08), powrót karetki (0xoD), wysuniĊcie wiersza (0x0A) i znak usuniĊcia (0x07), które są nadal powszechnie wykorzystywane. UĪycie danych znakowych w jĊzyku asemblera nie jest trudne i wiĊkszoĞü asemblerów pozwala na wykorzystywanie w programach znaków bez koniecznoĞci wyszukiwania ich wartoĞci szesnastkowej. Na przykáad zamiast zapisywaü: MOV

r0, #0x42

; przenieĞ ‘B’ do rejestru r0

moĪesz napisaü: MOV

r0, #'B'

; przenieĞ ‘B’ do rejestru r0

Dane znakowe bĊdą wykorzystywane w caáej ksiąĪce, wiĊc warto poĞwiĊciü nieco czasu na zaznajomienie siĊ z szesnastkowymi odpowiednikami alfabetu.

1.6. T’UMACZENIE BITÓW NA ROZKAZY Wszystkie procesory są programowane za pomocą zestawu instrukcji bĊdących niepowtarzalnymi wzorcami bitów lub zer i jedynek. KaĪdy zestaw jest charakterystyczny dla okreĞlonego procesora. Instrukcja moĪe informowaü procesor o koniecznoĞci dodania do siebie dwóch liczb, przeniesienia danych z jednego miejsca w drugie lub oczekiwania na zdarzenie, takie jak

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

1

40

1

Asembler dla procesorów ARM. PodrÚcznik programisty

naciĞniĊcie klawisza. Procesory firmy Intel, na przykáad Pentium 4, korzystają z zestawu wzorców bitowych, który jest caákowicie inny niĪ w przypadku procesora SPARC lub ARM926EJ-S. Jednak wszystkie zbiory instrukcji są do siebie zbliĪone i poznanie jednego z nich uáatwia zrozumienie niemal kaĪdego kolejnego. Same instrukcje mogą mieü róĪną dáugoĞü w zaleĪnoĞci od architektury procesora — 8, 16 lub 32 bity, a nawet kombinacje tych dáugoĞci. W naszym przypadku wszystkie instrukcje ARM mają 32 bity dáugoĞci; w dalszej czĊĞci ksiąĪki pokaĪemy, w jaki sposób procesory ARM mogą korzystaü z krótszych instrukcji, nazywanych THUMB. Czytanie i zapisywanie ciągów zer i jedynek szybko prowadzi do bólu gáowy, wiĊc w celu uáatwienia programowania okreĞlone wzorce bitowe są przeksztaácane na nazwĊ instrukcji lub kody mnemoniczne. W związku z tym zamiast zapisu: E0CC31B0 1AFFFFF1 E3A0D008

programista moĪe zapisaü STRH BNE MOV

sum, [pointer], #16 loop_one count, #8

co bĊdzie miaáo nieco wiĊcej sensu, gdy tylko poznasz same instrukcje. Przykïad 1.11. Weěmy pod uwagÚ wzorzec bitowy dla poniĝszych instrukcji: MOV

count, #8

Wzorzec ten jest liczbÈ szesnastkowÈ 0xE3A0D008. Na rysunku 1.10 moĝesz zauwaĝyÊ, ĝe procesor ARM oczekuje, ĝe poszczególne czÚĂci naszej instrukcji bÚdÚ umieszczone w zdefiniowanych polach — na przykïad cyfra 8 powinna byÊ umieszczona w polu o nazwie 8_bit_intermediate, a sama instrukcja, przeniesienie liczby do rejestru, jest zakodowana w polu o nazwie opcode. Parametr o nazwie count jest uïatwieniem pozwalajÈcym programiĂcie uĝywaÊ nazw zamiast numerów rejestrów. W innym miejscu naszego programu do zmiennej count jest przypisywany konkretny rejestr, a numer rejestru jest zakodowany w polu o nazwie Rd. Uĝycie instrukcji MOV pokaĝemy ponownie w rozdziale 6.

RYSUNEK 1.10. Instrukcja MOV

WiĊkszoĞü kodów mnemonicznych ma dáugoĞü kilku liter, na przykáad B dla skoku lub ADD dla dodawania. Projektanci mikroprocesorów zwykle próbują projektowaü kody mnemoniczne tak jasne, jak to tylko moĪliwe, ale co jakiĞ czas napotkasz coĞ takiego jak RSCNE (z procesora ARM), DCBZ (z procesora IBM) lub naprawdĊ niemoĪliwe do wymówienia AOBLSS (z procesora DEC). Pomimo tego, Īe taka nazwa jest czasami maáo zrozumiaáa, to i tak jest áatwiejsza do zapamiĊtania niĪ jej binarny lub szesnastkowy odpowiednik. Programowanie staáoby siĊ niemal niemoĪliwe, gdybyĞmy musieli zapamiĊtaü kaĪdy wzorzec polecenia. Transla-

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

PrzeglÈd systemów komputerowych

41

cjĊ moĪna wykonaü samodzielnie, wyszukując kod mnemoniczny w tabeli i zapisując odpowiadający mu wzorzec zer i jedynek, ale zajmuje to sporo czasu, a prawdopodobieĔstwo popeánienia báĊdu jest duĪe. Z tego powodu korzystamy z narzĊdzi wykonujących tĊ translacjĊ. Aby skomplikowaü sprawĊ, odczytywanie poleceĔ asemblera nie zawsze jest proste, nawet dla zaawansowanych programistów. Spójrzmy na sekwencjĊ kodów mnemonicznych dla architektury IA-32 firmy Intel: mov add mov cmp

eax, DWORD PTR _c eax, DWORD PTR _p DWORD PTR _a, eax DWORD PTR _a, 4

Jest to w miarĊ typowy kod — niezbyt egzotyczny. Jeszcze bardziej przeraĪający dla nowicjusza jest kod mnemoniczny dla mikroprocesorów ColdFire: mov.l mac.w mac.w

(0, %a2, %s2.1*4), %d6 %d6:u, #d5:u LDR r1, [PC, #N] ; gdzie N = przesuniĊcie do puli literaáów nr 1 LDR r2, =0xFFFFFFFF ; => MVN r2, #0 MOV pc, lr ; powrót z podprogramu LTORG ; pula literaáów nr 1 zawiera 0x55555555 LDR r3, =0x55555555 ; => LDR r3, [PC, #N] ; gdzie N = przesuniĊcie do puli literaáów nr 1 ; LDR r4, =0x66666666 ; jeĪeli nie bĊdzie tu komentarza, program zawiedzie ; pula literaáów nr 2 jest poza zasiĊgiem MOV pc, lr ; powrót z podprogramu SPACE 4200 END

; czyszczenie 4200 bajtów pamiĊci, ; tu zaczyna siĊ pusta ; pula literaáów nr 2

Ten spreparowany program wywoáuje dwa bardzo krótkie podprogramy za pomocą instrukcji skoku i záączenia (BL). NastĊpna instrukcja sáuĪy wyáącznie do zakoĔczenia programu, wiĊc na razie ją zignorujemy. Zwróü uwagĊ, Īe pierwszy podprogram, oznaczony etykietą func1, áaduje liczbĊ 42 do rejestru r0, co jest dosyü proste do wykonania za pomocą schematu rotacji bajtów. W rzeczywistoĞci nie jest potrzebna Īadna rotacja, poniewaĪ 0x2A mieĞci siĊ w bajcie. DziĊki temu asembler generuje instrukcjĊ MOV áadującą tĊ wartoĞü. NastĊpna wartoĞü 0x55555555 jest zbyt „dziwna”, aby moĪna ją byáo utworzyü za pomocą schematu rotacji, dlatego asembler jest zmuszony do wygenerowania puli literaáów, która bĊdzie siĊ zaczynaü po 4200 bajtach zarezerwowanych na koĔcu programu. Jednak instrukcja áadowania nie moĪe siĊgnąü tak daleko i jeĪeli nie zrobimy nic w celu rozwiązania tego problemu, asembler zwróci báąd. Druga instrukcja áadowania uĪyta w podprogramie, która ustawia wszystkie bity w rejestrze r2,

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

6

100

Asembler dla procesorów ARM. PodrÚcznik programisty

moĪe byü wykonana za pomocą MVN. Ostatnia instrukcja podprogramu przenosi wartoĞü z rejestru áączącego (r14) z powrotem do licznika programu (r15), wymuszając na procesorze powrót do instrukcji nastĊpującej po pierwszej instrukcji BL. Nie przejmuj siĊ na razie podprogramami, poniewaĪ w dalszej czĊĞci ksiąĪki znajduje siĊ caáy podrozdziaá im poĞwiĊcony. Przez uĪycie dyrektywy LTORG na koĔcu pierwszego podprogramu wymusiliĞmy na asemblerze zbudowanie puli literaáów pomiĊdzy dwoma podprogramami w pamiĊci, jak jest to pokazane na rysunku 6.5. Pula ta pokazuje adresy pamiĊci, instrukcje i kody mnemoniczne wygenerowane przez asembler. NaleĪy równieĪ zauwaĪyü, Īe instrukcja LDR pod adresem 0x18 w naszym przykáadzie jest reprezentowana jako: LDR r1, [PC,#0x0008]

6

co wymaga wyjaĞnienia. Jak pokazaliĞmy w rozdziale 5., ten typ instrukcji áadowania informuje procesor, aby uĪyá licznika programu (który zawsze zawiera adres instrukcji pobieranej z pamiĊci), zmodyfikowaá jego wartoĞü (w tym przypadku dodaá do niej liczbĊ 8), a nastĊpnie uĪyá nowej wartoĞci jako adresu. Gdy skorzystamy z dyrektywy LTORG i poinformujemy asembler, by umieĞciá pulĊ literaáów pomiĊdzy podprogramami w pamiĊci, korygujemy poáoĪenie naszych staáych i asembler moĪe wyliczyü, jak daleko te staáe leĪą od adresu w liczniku programu. WaĪne jest, aby sprawdziü, gdzie wskazuje licznik programu, gdy instrukcja LDR znajduje siĊ w fazie wykonania potoku. Wracając jeszcze raz do rysunku 6.5, moĪemy zauwaĪyü, Īe gdy instrukcja LDR jest w fazie wykonania potoku ARM7TDMI, instrukcja MOV znajduje siĊ w fazie pobierania. Dlatego odlegáoĞü pomiĊdzy adresem 0x20 (znajdującym siĊ w PC) a potrzebnym do pobrania naszej staáej, czyli 0x28, wynosi 8. W związku z tym takiej wartoĞci naleĪy uĪyü jako przesuniĊcia do zmodyfikowania rejestru PC w instrukcji LDR. Na szczĊĞcie nie musimy obliczaü tych przesuniĊü samodzielnie — asembler zrobi to za nas.

RYSUNEK 6.5. Dezasemblacja podprogramu

W drugim podprogramie znajdują siĊ jeszcze dwie staáe, z których tylko jedna jest przeksztaácana na instrukcjĊ, poniewaĪ umieĞciliĞmy komentarz w drugiej instrukcji áadowania. ZauwaĪ, Īe na rysunku 6.5 instrukcja pod adresem 0x2C zawiera kolejny adres wzglĊdny do PC, ale tym razem przesuniĊcie jest ujemne. Okazuje siĊ, Īe instrukcja moĪe wspóádzieliü dane znajdujące siĊ juĪ w puli literaáów. PoniewaĪ asembler wáaĞnie wygenerowaá tĊ staáą dla pierwszego podprogramu, a dodatkowo znajduje siĊ ona bardzo blisko instrukcji (w zakresie 4 KB),

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

Staïe i pule literaïów

101

moĪesz po prostu odjąü 12 od wartoĞci licznika programu w momencie, gdy instrukcja LDR znajduje siĊ w fazie wykonania potoku (dla wszystkich uwaĪnych czytelników: wydaje siĊ, Īe licznik programu pobraá nastĊpną instrukcjĊ poza naszym maáym programem — to problem czy nie?). Druga instrukcja áadowania zostaáa oznaczona komentarzem, aby zapobiec powstaniu báĊdu asemblera. PoniewaĪ umieĞciliĞmy na koĔcu programu tabelĊ o wielkoĞci 4200 bajtów, najbliĪsza pula literaáów jest teraz oddalona o wiĊcej niĪ 4 KB i asembler nie moĪe zbudowaü instrukcji siĊgającej do tej wartoĞci w pamiĊci. Aby to poprawiü, naleĪy uĪyü kolejnej dyrektywy LTORG przed tabelą. Podsumowując: • Korzystaj z LDR , =, aby umieĞciü staáą w rejestrze. • Staáe literaáów są generowane na koĔcu kaĪdej sekcji kodu. • Asembler sprawdzi, czy staáa jest juĪ dostĊpna w puli literaáów, i jeĪeli tak bĊdzie, spróbuje zaadresowaü istniejącą staáą. • Asembler spróbuje umieĞciü staáą w nastĊpnej puli literaáów, jeĪeli nie jest juĪ dostĊpna. JeĞli nastĊpna pula literaáów jest poza zasiĊgiem, asembler wygeneruje báąd i zajdzie koniecznoĞü poprawienia kodu, najprawdopodobniej za pomocą LTORG. • JeĪeli bĊdziesz korzystaü z LTORG, naleĪy umieĞciü tĊ dyrektywĊ po pseudoinstrukcji LDR powodującej báąd, w zakresie ±4 KB. Pule literaáów trzeba umieszczaü tam, gdzie procesor nie bĊdzie próbowaá wykonaü danych jako instrukcji, najlepiej po instrukcji skoku bezwarunkowego lub na koĔcu podprogramu.

6.4. ’ADOWANIE ADRESÓW DO REJESTRÓW W pewnym momencie bĊdziesz potrzebowaá zaáadowaü adres etykiety lub symbolu do rejestru. Zwykle robimy to przez podanie punktu startowego tabeli, listy lub ewentualnie zbioru wspóáczynników potrzebnych w filtrze cyfrowym. Dla przykáadu przeanalizujmy poniĪszy fragment kodu: SRAM_BASE AREA dest image coeff pointer

EQU

0x04000000

FILTER, CODE RN 0 ; wskaĨnik docelowy RN 1 ; wskaĨnik danych obrazu RN 2 ; wskaĨnik tabeli wspóáczynników RN 3 ; wskaĨnik tymczasowy

ENTRY CODE32 Main ; obszar inicjalizacji LDR dest, =#SRAM_BASE MOV pointer, dest ADR image, image_data ADR coeff, cosines BL filter . . . ALIGN image_data

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

; przeniesienie adresu bazowego pamiĊci do dest ; bieĪący wskaĨnik jest celem ; zaáadowanie wskaĨnika danych obrazu ; áadowanie wskaĨnika wspóáczynników ; wykonanie jednego przebiegu filtra

6

102

6

Asembler dla procesorów ARM. PodrÚcznik programisty DCW DCW

0x0001,0x0002,0x0003,0x0004 0x0005,0x0006,0x0007,0x0008

. . . cosines DCW DCW . . . END

0x3ec5,0x3537,0x238e,0x0c7c 0xf384,0xdc72,0xcac9,0xc13b

Choü wiĊkszoĞü programu nadal jest do napisania, moĪna zauwaĪyü, Īe jeĪeli bĊdziemy konfigurowaü algorytm, na przykáad filtr cyfrowy, w którym czĊĞü danych i czĊĞü wspóáczynników jest przechowywana w pamiĊci, powinniĞmy ustawiü wskaĨniki na początku kaĪdego zestawu. Tym sposobem rejestr bĊdzie przechowywaá adres początkowy. Aby odwoáaü siĊ do okreĞlonej danej, bĊdziemy po prostu uĪywaü rejestru zawierającego wáaĞciwe przesuniĊcie. Dyrektywy EQU i RN przedstawiliĞmy juĪ w rozdziale 4., ale teraz rzeczywiĞcie zaczynamy z nich korzystaü. W pierwszym wierszu przyrównujemy etykietĊ SRAM_BASE do liczby, dziĊki czemu nie musimy za kaĪdym razem wpisywaü dáugiego adresu, podobnie jak w przypadku instrukcji #DEFINE w jĊzyku C. Dyrektywa RN pozwala nadaü nazwy naszym rejestrom r0, r1, r2 i r3, przez co moĪemy siĊ do nich odwoáywaü za pomocą nazwy funkcji, a nie liczby. Nie trzeba tego robiü, ale czĊsto warto znaü zastosowanie rejestru przy programowaniu. Pierwsze dwie instrukcje áadują znane adresy (nazwane adresami bezwzglĊdnymi, poniewaĪ nie przesuwają siĊ, jeĪeli relokujesz kod w pamiĊci) do rejestrów r0 i r3. Trzecia i czwarta instrukcja jest pseudoinstrukcją ADR, co jest szczególnie uĪyteczne przy áadowaniu adresu do rejestru. Dlaczego wykonujemy to w ten sposób? ZaáóĪmy, Īe ta sekcja kodu byáa uĪywana razem z innymi blokami. Nie musimy dokáadnie wiedzieü, gdzie zaczynają siĊ dane po asemblacji dwóch sekcji, wiĊc áatwiej jest pozwoliü asemblerowi na obliczenie adresów. Przykáadowo jeĪeli image_data faktycznie zaczyna siĊ w pamiĊci od adresu 0x8000, to ten adres zostanie przeniesiony do rejestru r1, któremu nadaliĞmy nową nazwĊ. JeĞli jednak zmienimy kod, przeniesiemy dane obrazu lub doáączymy kolejny blok kodu, to adres ten ulegnie zmianie. Przy uĪyciu ADR nie musimy siĊ obawiaü o adres. Przykïad 6.2. Przeanalizujmy kolejny przykïad, tym razem pokazujÈcy, w jaki sposób pseudoinstrukcja ADR jest konwertowana na rzeczywiste instrukcje ARM. Ponownie kod tego przykïadu nie wykonuje nic poza ustawieniem wskaěników, jego zadaniem jest ilustracja dziaïania ADR. AREA adrlabel, CODE,READONLY ENTRY ; oznaczenie pierwszej instrukcji do wykonania Start stop func

BL func B stop LTORG ADR r0, Start ADR r1, DataArea

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

; skok do podprogramu ; stop ; utworzenie puli literaáów ; => SUB r0, PC, #przesuniĊcie do Start ; => ADD r1, PC, #przesuniĊcie do DataArea

Staïe i pule literaïów

; ADR r2, DataArea+4300 ADRL r2, DataArea+4300 MOV pc, lr DataArea

SPACE 8000

103

; nie uda siĊ, poniewaĪ przesuniĊcie nie ; moĪe byü wyraĪone przez drugi operand ADD ; => ADD r2, PC, #przesuniĊcie1 ; ADD r2, r2, #przesuniĊcie2 ; powrót ; zaczynając od bieĪącej lokalizacji, ; czyĞci obszar 8000 bajtów pamiĊci ; zerami

END

ZwróÊ uwagÚ, ĝe program wywoïuje podprogram o nazwie func za pomocÈ operacji skoku i zïÈczenia (BL). NastÚpne trzy instrukcje sïuĝÈ do zakoñczenia programu, wiÚc musimy tylko sprawdziÊ, co dzieje siÚ po dyrektywie LTORG. Podprogram zaczyna siÚ od etykiety func oraz pseudoinstrukcji ADR sïuĝÈcej do zaïadowania adresu poczÈtkowego naszego gïównego programu do rejestru r0. Asembler tworzy wiÚc albo instrukcjÚ ADD, albo SUB wykorzystujÈce licznik programu. Podobnie w przypadku przedstawionej wczeĂniej pseudoinstrukcji LDR dziÚki znajomoĂci wartoĂci licznika programu w czasie, gdy instrukcje ADD lub SUB trafiïy do fazy wykonania w potoku, moĝemy pobraÊ wartoĂÊ licznika i zmodyfikowaÊ jÈ, aby wygenerowaÊ adres. Adres ten nie moĝe byÊ oddalony o wiÚcej niĝ 255 bajtów, jeĝeli nie jest wyrównany do sïowa (czyli nie koñczy siÚ na 0, 4, 8 lub C), lub wiÚcej niĝ 255 sïów, jeĂli jest wyrównany do sïowa. Jeĝeli tak siÚ zdarzy, asembler wygeneruje komunikat bïÚdu informujÈcy, ĝe operacji nie moĝna wykonaÊ za pomocÈ jednej instrukcji. JeĂli spojrzymy na drugÈ pseudoinstrukcjÚ ADR w tym przykïadzie, widaÊ, ĝe odlegïoĂÊ pomiÚdzy instrukcjÈ a etykietÈ DataArea jest na tyle maïa, ĝe do wygenerowania staïej asembler uĝyje prostej instrukcji ADD. Trzecia pseudoinstrukcja ADR próbuje utworzyÊ adres dla instrukcji umieszczonej za 8000-bajtowym blokiem pamiÚci. To nie zadziaïa, ale moĝna w tym przypadku uĝyÊ innej pseudoinstrukcji: ADRL. Za pomocÈ dwóch operacji zamiast jednej ADRL oblicza przesuniÚcie w zakresie ±64 KB dla adresów niewyrównanych wzglÚdem sïowa i ±256 KB dla adresów wyrównanych do sïowa. PowinieneĂ zwróciÊ uwagÚ, ĝe jeĝeli w kodzie uĝyjemy pseudoinstrukcji ADRL, wygenerowane zostanÈ dwie operacje nawet w przypadku, gdy wystarczajÈca jest tylko jedna, wiÚc tej instrukcji naleĝy uĝywaÊ z rozwagÈ w pÚtlach, w których liczba cykli zegara jest waĝna. Warto jeszcze wspomnieÊ, ĝe etykieta wykorzystana w ADR lub ADRL musi znajdowaÊ siÚ w tej samej sekcji kodu. Jeĝeli etykieta jest poza zasiÚgiem w tej samej sekcji kodu, asembler nie bÚdzie mógï wygenerowaÊ odwoïania. Jeĝeli etykieta jest poza zasiÚgiem w innej sekcji kodu, odwoïania nie bÚdzie mógï wygenerowaÊ linker.

Istnieje jeszcze jeden sposób áadowania adresów do rejestrów, identyczny z tym przedstawionym przy pseudoinstrukcji LDR. Skáadnia jest nastĊpująca: LDR , =etykieta

W tym przypadku asembler konwertuje pseudoinstrukcje na instrukcje áadowania, w których adres jest pobierany z utworzonej do tego celu puli literaáów. Podobnie jak w przypadku áadowania staáych, naleĪy upewniü siĊ, Īe pula literaáów znajduje siĊ w zasiĊgu instrukcji. Ta pseudoinstrukcja róĪni siĊ od ADR i ADRL tym, Īe moĪna przy jej uĪyciu odwoáywaü siĊ do etykiet spoza bieĪącej sekcji, a linker utworzy odwoáanie w procesie konsolidacji.

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

6

104

Asembler dla procesorów ARM. PodrÚcznik programisty

Przykïad 6.3. Poniĝszy przykïad ilustruje kilka sposobów uĝycia pseudoinstrukcji LDR, w tym korzystajÈcych z etykiet i przesuniÚÊ. AREA LDRlabel, CODE,READONLY ENTRY ; oznaczenie pierwszej instrukcji do wykonania start stop func1

BL func1 BL func2 B stop

; skok do pierwszego podprogramu ; skok do drugiego podprogramu ; zakoĔczenie

LDR r0, =start

; => LDR R0, [PC, #przesuniĊcie do ; puli literaáów nr 1] ; => LDR R1, [PC, #przesuniĊcie do ; puli literaáów nr 1] ; => LDR R2, [PC, #przesuniĊcie do ; puli literaáów nr 1] ; powrót ; pula literaáów nr 1

LDR r1, =Darea + 12

6

LDR r2, =Darea + 6000 MOV pc,lr LTORG func2

LDR r3, =Darea + 6000

; LDR r4, =Darea+6004

Darea

MOV pc, lr SPACE 8000

END

; => LDR r3, [PC, #przesuniĊcie do ; puli literaáów nr 1] ; (wspóádzielonej z poprzednim ; literaáem) ; jeĪeli komentarz zostanie usuniĊty, ; spowoduje báąd, ; poniewaĪ pula literaáów nr 2 jest ; poza zasiĊgiem ; powrót ; zaczynając od bieĪącej ; lokalizacji, ; czyĞcimy 8000-bajtowy obszar danych ; pamiĊci, wypeániając go zerami ; pula literaáów nr 2 jest poza ; zasiĊgiem instrukcji LDR

Moĝna zauwaĝyÊ, ĝe pierwsze trzy instrukcje LDR w podprogramie func1 zostanÈ przeksztaïcone na ïadowanie wzglÚdne do PC z puli literaïów, która bÚdzie utworzona w pamiÚci w miejscu dyrektywy LTORG. Dodatkowo pierwsza instrukcja ïadowania w drugim podprogramie moĝe korzystaÊ z tej samej puli literaïów do utworzenia przesuniÚcia wzglÚdem PC. Poniewaĝ dyrektywa SPACE czyĂci 8000-bajtowy blok pamiÚci, druga instrukcja ïadowania nie moĝe osiÈgnÈÊ drugiej puli literaïów, poniewaĝ musi byÊ ona w granicach 4 KB.

Podsumowując: • JeĪeli tylko jest to moĪliwe, korzystaj z pseudoinstrukcji ADR , etykieta

do umieszczania adresu w rejestrze. Adres nie moĪe byü oddalony o ponad 255 bajtów, jeĪeli nie jest wyrównany do sáowa, lub wiĊcej niĪ 255 sáów, jeĪeli jest wyrównany do sáowa.

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

Staïe i pule literaïów

105

• JeĞli powyĪszy warunek nie jest speániony, uĪyj pseudoinstrukcji ADRL, która oblicza przesuniĊcie w zakresie ±64 KB dla adresów niewyrównanych wzglĊdem sáowa i ±256 KB dla adresów wyrównanych do sáowa. Zwróü uwagĊ, Īe jeĪeli uĪywasz w swoim kodzie pseudoinstrukcji ADRL, wygenerowane zostaną dwie operacje, nawet wtedy, gdy wystarczy jedna. • Korzystaj z pseudoinstrukcji LDR , =etykieta

jeĪeli planujesz odwoáywaü siĊ do etykiet w innych sekcjach kodu lub wiesz, Īe bĊdzie istniaáa tabela literaáów i nie przeszkadzają Ci dodatkowe cykle potrzebne do pobrania literaáu do pamiĊci. Zachowaj ostroĪnoĞü przy korzystaniu z pul literaáów uĪywanych dla konstrukcji: LDR , =stađa

6.5. mWICZENIA 1. Jaka staáa bĊdzie zaáadowana do rejestru r7 po wykonaniu poniĪszych instrukcji? a) MOV r7, #0x8C, 4 b) MOV r7, #0x42, 30 c) MVN r7, #2 d) MVN r7, #0x8C, 4 2. Korzystając ze schematu rotacji bajtów opisanego w tym rozdziale, okreĞl instrukcjĊ i rotacjĊ potrzebną do zaáadowania poniĪszych staáych do rejestru r2: a) 0xA400 b) 0x7D8 c) 0x17400 d) 0x1980 3. OkreĞl, czy poniĪsze staáe mogą byü zaáadowane do rejestru za pomocą jednej instrukcji bez tworzenia puli literaáów: a) 0x12340000 b) 0x77777777 c) 0xFFFFFFFF d) 0xFFFFFFFE 4. Jaki jest najlepszy sposób na umieszczenie staáej numerycznej w rejestrze? 5. Gdzie najlepiej umieszczaü dane w puli literaáów? 6. ZaáóĪmy, Īe mamy nastĊpujący kod: AREA SAMPLE, CODE,READONLY ENTRY start MOV r12, #SRAM_BASE ADD r0, r1, r2 MOV r0, #0x18 BL routine1 .

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

6

106

Asembler dla procesorów ARM. PodrÚcznik programisty . . routine1 STM sp!, {r0-r3,lr} . . . END

Opisz dwa sposoby zaáadowania etykiety routine1 do rejestru r3 i podaj wszystkie zastrzeĪenia. 7. Opisz róĪnicĊ pomiĊdzy ADR a ADRL.

6

8. Podaj instrukcje pozwalające na wykonanie poniĪszych operacji: a) Dodanie 0xEC00 do rejestru r6 i umieszczenie sumy w rejestrze r4. b) OdjĊcie 0xFF000000 od rejestru r12 i umieszczenie wyniku w rejestrze r7. c) Dodanie wartoĞci 0x123456AB od rejestru r7 i umieszczenie sumy w rejestrze r12. d) Umieszczenie –1 w notacji z uzupeánieniem do dwójki w rejestrze r3. 9. ZaáóĪmy, Īe mamy nastĊpujący kod:

stop func1

func2 BigTable

AREA EXERCISE, CODE ENTRY BL func1 BL func2 B stop MOV r2, #0 LDR r1, =0xBABEFACE LDR r2, =0xFFFFFFFC MOV pc, lr LTORG LDR r3, =0xBABEFACE LDR r4, =0x66666666 MOV pc, lr SPACE 3700

; wywoáanie pierwszego podprogramu ; wywoáanie drugiego podprogramu ; zakoĔczenie programu

; powrót z podprogramu ; pula literaáów nr 1 zawiera 0xBABEFACE

; powrót z podprogramu ; czyszczenie 3700 bajtów pamiĊci ; zaczynających siĊ w tym miejscu

END

Czy zaáadowanie 0x66666666 do rejestru r4 spowoduje báąd? Dlaczego lub dlaczego nie? 10. Instrukcja skoku ARM — B — zapewnia zasiĊg skoku ±32 MB. JeĪeli licznik programu ma wartoĞü 0x8000 i musisz skoczyü do adresu 0xFF000000, to jak moĪesz zrealizowaü taką operacjĊ?

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

Rozdziaï 7 Operacje logiczne i arytmetyczne 7 7.1. WST}P Jest to dáugi rozdziaá, ale są ku temu powody. Operacje arytmetyczne są prawdopodobnie jednymi z najczĊĞciej uĪywanych typów instrukcji, szczególnie jeĪeli pisane oprogramowanie manipuluje duĪymi porcjami danych, na przykáad przychodzącym sygnaáem audio. Algorytmy graficzne, algorytmy przetwarzania mowy, kontrolery cyfrowe oraz algorytmy przetwarzanie dĨwiĊku wymagają duĪej liczby obliczeĔ, wiĊc waĪne jest, aby poznaü dostĊpne typy danych oraz sposoby wykonania operacji w moĪliwie najkrótszym czasie i (lub) z wykorzystaniem najmniejszej iloĞci pamiĊci. Zaczniemy od przedstawienia znaczników, zaprezentujemy podstawowe instrukcje arytmetyczne, a rozdziaá zakoĔczymy przeglądem arytmetyki wykorzystującej uáamki. Gdy dobrze zrozumiesz koncepcje znajdujące zastosowanie w cyfrowej arytmetyce, bĊdziesz w stanie przejĞü do bardziej zaawansowanych funkcji, takich jak funkcje trygonometryczne, wykáadnicze oraz pierwiastki.

7.2. ZNACZNIKI I ICH WYKORZYSTYWANIE Jak pamiĊtasz z rozdziaáu 2., rejestr Current Program Status Register zawiera znaczniki, dane o bieĪącym stanie komputera oraz trybie pracy przedstawione jako wartoĞci bitów pokazane na rysunku 7.1. W górnej czĊĞci rejestru dostĊpne są cztery bity pozwalające okreĞliü, czy instrukcja powinna byü wykonana warunkowo, czy nie. Znaczniki są ustawiane i kasowane na podstawie dwóch operacji: albo instrukcji uĪywanej specjalnie do ustawienia lub wyczyszczenia znaczników, albo instrukcji, która zostaáa „poinformowana”, przez doáączenie do jej kodu mnemonicznego litery „S”, o tym, Īe na podstawie wyniku jej wykonania mają byü ustawione bity. Na przykáad EORS oblicza róĪnicĊ symetryczną, a nastĊpnie ustawia znaczniki, poniewaĪ w tej instrukcji ustawiony jest bit S. Bitu tego moĪna uĪyü we wszystkich instrukcjach ALU (jednostki arytmetyczno-logicznej), wiĊc moĪemy sterowaü tym, czy znaczniki są ustawiane, czy nie. Przyjrzyjmy siĊ kaĪdemu znacznikowi z osobna — niektóre są bardzo proste, a niektóre wymagają przemyĞlenia.

107 Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

108

Asembler dla procesorów ARM. PodrÚcznik programisty

RYSUNEK 7.1. Rejestr Current Program Status Register

7.2.1. ZNACZNIK N Znacznik ten jest uĪywany do sprawdzania wyniku ujemnego. Co to znaczy ujemnego? Definicja wyniku ujemnego bazuje na systemie liczb z uzupeánieniem do dwójki, a jak widziaáeĞ w ostatnich kilku rozdziaáach, liczba z dopeánieniem do dwójki jest uwaĪana za ujemną, jeĪeli jest ustawiony jej najbardziej znaczący bit. NaleĪy jednak zachowaü ostroĪnoĞü, poniewaĪ moĪemy dodaü do siebie dwie liczby dodatnie i otrzymamy wartoĞü z ustawionym najbardziej znaczącym bitem.

7

Przykïad 7.1. Dodanie –1 do –2 jest bardzo ïatwe, a wynik ma ustawiony najbardziej znaczÈcy bit, jak siÚ tego spodziewaliĂmy. W notacji z dopeïnieniem do dwójki operacja ta jest reprezentowana jako: FFFFFFFF + FFFFFFFE ---------FFFFFFFD

Przykïad 7.2. Jeĝeli dodamy poniĝsze wartoĂci, to pomimo ĝe skïadniki sÈ dodatnie w zapisie z dopeïnieniem do dwójki, suma jest ujemna: 7B000000 + 30000000 ---------AB000000

co oznacza, ĝe czasami moĝna siÚ pomyliÊ. Na poczÈtek zwróÊ uwagÚ, ĝe poniewaĝ najbardziej znaczÈcy bit jest ustawiony, konieczne jest ustawienie bitu N, jeĝeli nasza instrukcja ADD powinna ustawiÊ znaczniki (jak pamiÚtamy, nie musi tego robiÊ). Po drugie, jeĂli nie korzystamy z liczb z dopeïnieniem do dwójki, to prawdopodobnie nie musimy przejmowaÊ siÚ wartoĂciÈ bitu N. Na koniec warto pamiÚtaÊ, ĝe w reprezentacji z dopeïnieniem do dwójki suma dwóch liczb dodatnich daje wiÚkszÈ liczbÚ dodatniÈ, ale powyĝszy wynik pokazuje, ĝe ta suma liczb dodatnich nie moĝe byÊ reprezentowana za pomocÈ 32 bitów, wiÚc w efekcie powstaje przepeïnienie ponad dostÚpnÈ precyzjÚ liczb. Z tego powodu do pracy z wartoĂciami ze znakiem potrzebujemy wiÚcej znaczników.

7.2.2. ZNACZNIK V JeĪeli przy wykonywaniu takich operacji jak dodawanie lub odejmowanie okreĞlimy wartoĞü znacznika V jako operacjĊ XOR bitu przeniesienia wchodzącego do najbardziej znaczącego bitu wyniku z bitem przeniesienia wychodzącym z najbardziej znaczącego bitu, to znacznik V

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

Operacje logiczne i arytmetyczne

109

w precyzyjny sposób wskaĪe nam przepeánienie przy operacjach ze znakiem. Przepeánienie nastĊpuje, gdy wynik dodawania, odejmowania lub porównywania jest wiĊkszy lub równy 231 lub mniejszy niĪ –231. Przykïad 7.3. Dodajmy do siebie dwie wartoĂci ze znakiem, reprezentowane w postaci dopeïnienia do dwójki: A1234567 + B0000000 ---------151234567

Wynik nie mieĂci siÚ w 32 bitach. Co waĝniejsze, poniewaĝ liczby sÈ zapisane w postaci dopeïnienia do dwójki, a dodajemy do siebie dwie dosyÊ duĝe liczby ujemne, to przy przepeïnieniu najbardziej znaczÈcy bit 32-bitowego wyniku jest czyszczony (zwróÊ uwagÚ na cyfrÚ 5 w najbardziej znaczÈcym bajcie wyniku).

Przeanalizujmy ponownie przykáad 7.2. Gdy dodaliĞmy 0x7B000000 do 0x30000000, wynik zmieĞciá siĊ w 32 bitach. Jednak wynik moĪe byü interpretowany jako ujemny, kiedy dodamy dwie liczby dodatnie, wiĊc czy jest to przypadek przepeánienia? OdpowiedĨ brzmi: tak.

7.2.3. ZNACZNIK Z Jest to jeden z najáatwiejszych do zrozumienia znaczników, poniewaĪ informuje nas, Īe wynikiem operacji byáo zero, czyli wszystkie 32 bity byáy ustawione na zero.

7.2.4. ZNACZNIK C Znacznik przeniesienia jest ustawiany, jeĪeli wynik dodawania jest wiĊkszy lub równy 232, jeĞli wynik odejmowania jest dodatni lub w wyniku operacji na cyklicznym rejestrze przesuwnym w instrukcji kopiowania albo logicznej. Przeniesienie jest przydatnym znacznikiem, poniewaĪ pozwala budowaü operacje o wiĊkszej dokáadnoĞci, na przykáad dodawania liczb 64-bitowych, co pokaĪemy nieco dalej.

7.3. INSTRUKCJE PORÓWNANIA Oprócz uĪycia bitu S w instrukcji do ustawiania znaczników sáuĪą cztery instrukcje, które nie robią nic poza ustawianiem kodów warunku lub sprawdzaniem okreĞlonych bitów w rejestrze. Są to: • CMP — porównanie. CMP odejmuje wartoĞü rejestru lub literaá od wartoĞci rejestru i aktualizuje kody warunku. Za pomocą CMP moĪemy szybko porównaü zawartoĞü rejestru z okreĞloną wartoĞcią, na przykáad na początku lub na koĔcu pĊtli. • CMN — porównanie ujemne. CMN dodaje wartoĞü rejestru lub literaá do wartoĞci rejestru i aktualizuje kody warunku. CMN pozwala równieĪ szybko sprawdziü zawartoĞü rejestru. Instrukcja ta jest odwrotnoĞcią CMP, a asembler bĊdzie zastĊpowaá instrukcje CMP, jeĪeli jest to wáaĞciwe. Na przykáad gdy wpiszemy polecenie:

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

7

110

Asembler dla procesorów ARM. PodrÚcznik programisty CMP r0, #-20

to asembler wygeneruje CMN r0, #0x14

• TST — test. TST wykonuje logiczną operacjĊ AND z wartoĞcią rejestru i aktualizuje kody warunku bez wpáywania na znacznik V. Za pomocą TST moĪemy sprawdziü, czy okreĞlone bity rejestru są wyzerowane lub czy co najmniej jeden bit rejestru jest ustawiony. • TEQ — test odpowiednioĞci. TEQ wykonuje logiczną operacjĊ XOR z wartoĞcią rejestru i aktualizuje kody warunku bez wpáywania na znacznik V. Za pomocą TEQ moĪemy sprawdziü, czy dwie wartoĞci są takie same. Skáadnia tych funkcji jest nastĊpująca: instrukcja{} ,

7

gdzie {} jest jednym z opcjonalnych warunków przedstawionych w rozdziale 8., a moĪe byü rejestrem z opcjonalnym przesuniĊciem lub wartoĞcią. Typowe instrukcje mogą wyglądaü nastĊpująco: CMP BEQ

r8, #0 routine

TEQ

r9, r4, LSL #3

; r8==0? ; tak, wiĊc przejdĨ do routine

Jak pamiĊtasz, znaczniki kodów warunku są przechowywane w rejestrze Current Program Status Register, razem z informacją o trybie i stanie procesora. MoĪemy skorzystaü z instrukcji MRS (przenieĞ PSR do rejestru ogólnego) do odczytania znaczników w CPSR i dowolnym SPSR, poniewaĪ instrukcja ta áaduje kopiĊ caáego rejestru stanu procesora do rejestru ogólnego przeznaczenia. Na przykáad poniĪsze dwie instrukcje MRS r0, CPSR MRS r1, SPSR

áadują zawartoĞü CPSR i SPSR do rejestrów odpowiednio r0 i r1. DziĊki temu moĪemy w dowolny sposób sprawdzaü stan znaczników. Nie moĪna jednak wykorzystaü rejestru r15 jako docelowego ani nie moĪna odwoáywaü siĊ do SPSR w trybie User, poniewaĪ w tym przypadku on nie istnieje. W dokumencie ARM Architectural Reference Manual (ARM 2007b) zdefiniowano wynik tej operacji jako UNPREDICTABLE. Trzeba pamiĊtaü, Īe powinniĞmy korzystaü z kodów warunku razem z instrukcją skoku (B) lub innymi instrukcjami do tworzenia pĊtli i warunkowych podprogramów asemblera, bez koniecznoĞci odczytywania znaczników, np. tak jak w pokazanej powyĪej instrukcji BEQ. Temat ten przedstawiamy dokáadniej w rozdziale 8.

7.4. OPERACJE PRZETWARZANIA DANYCH Jak moĪna oczekiwaü, kaĪdy mikroprocesor, nawet ten najprostszy, udostĊpnia podstawowe operacje, takie jak dodawanie, odejmowanie i przesuniĊcia, na podstawie których moĪna budowaü bardziej zaawansowane operacje, jak dzielenie, mnoĪenie i pierwiastkowanie. Mikroprocesory ARM są zaprojektowane do wykorzystania w zastosowaniach wbudowanych, w których bardzo waĪne jest zuĪycie energii i wielkoĞü ukáadu. W idealnej sytuacji procesor powinien oferowaü szeroką gamĊ instrukcji przetwarzania bez uĪycia zbyt wielu bramek logicznych

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

Operacje logiczne i arytmetyczne

111

i bez zwiĊkszania powierzchni ukáadu. DziĊki poáączeniu cyklicznego rejestru przesuwnego, 32-bitowej jednostki arytmetyczno-logicznej (ALU) oraz sprzĊtowego ukáadu mnoĪenia procesor ARM7TDMI oferuje bogaty zestaw instrukcji przy niewielkim zuĪyciu energii. Przykáadowa operacja przetwarzania danych, ADD, wygląda nastĊpująco: ADDS{} r0, r1,

gdzie {} jest jednym z opcjonalnych warunków przedstawionych w rozdziale 8. Drugi operand, , moĪe byü bezpoĞrednią wartoĞcią, rejestrem lub rejestrem ze skojarzonym z nim przesuniĊciem albo rotacją. Ostatnia opcja okazuje siĊ bardzo wygodna, co pokaĪemy w kolejnych punktach. Warto teĪ pamiĊtaü, Īe niedawno skáadnia zostaáa zmodyfikowana na potrzeby UAL (Unified Assembly Language) — w starej wersji kodów mnemonicznych tĊ instrukcjĊ zapisujemy jako ADD{}S1.

7.4.1. OPERACJE LOGICZNE ARM obsáuguje operacje logiki Boolowskiej wykorzystujące dwa operandy zamieszczone w tabeli 7.1. Choü w poprzednich rozdziaáach spotkaáeĞ siĊ juĪ z instrukcją MOV, to warto wiedzieü, Īe instrukcja MOVN moĪe byü uĪyta do odwrócenia wszystkich bitów w rejestrze, poniewaĪ jako operandu oczekuje negacji z dopeánieniem do jedynki. Bardzo szybkim sposobem na zaáadowanie reprezentacji liczby –1 w dopeánieniu do dwójki jest logiczne odwrócenie zera, poniewaĪ 32-bitowa wartoĞü 0xFFFFFFFF to wáaĞnie –1 w notacji z dopeánieniem do dwójki, co moĪna zapisaü jako: MOVN r5, #0

; r5 = –1 w notacji z dopeánieniem do dwójki

TABELA 7.1. Operacje logiczne Instrukcja

Komentarz

AND

Logiczna operacja AND na dwóch operandach.

ORR

Logiczna operacja OR na dwóch operandach.

EOR

Logiczna operacja XOR na dwóch operandach.

MOVN

Przeniesienie z odwróceniem — logiczna operacja NOT na wszystkich bitach.

BIC

Wyczyszczenie bitów — wyczyszczenie wybranych bitów w rejestrze.

Przykáady zastosowania tych operatorów są przedstawione poniĪej: AND ORR EOR BIC

r1, r1, r1, r1,

r2, r2, r2, r2,

r3 r3 r3 r3

; r1 = r2 AND r3 ; r1 = r2 OR r3 ; r1 = r2 XOR r3 ; r1 = r2 AND NOT r3

Pierwsze trzy instrukcje są dosyü proste — AND, OR i XOR to podstawowe funkcje logiczne. Czwarta instrukcja jest operacją czyszczenia bitów, która moĪe byü uĪywana do wyczyszczenia wybranych bitów w rejestrze. Dla kaĪdego bitu w drugim operandzie wartoĞü 1 czyĞci odpowiedni

1 Ta ksiąĪka zostaáa wydana w czasie przechodzenia na UAL; najprawdopodobniej spotkasz siĊ z obydwoma formatami instrukcji.

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

7

112

Asembler dla procesorów ARM. PodrÚcznik programisty

bit pierwszego operandu (rejestr), a 0 pozostawia go bez zmian. Zgodnie z formatem instrukcji przetwarzania danych dla drugiego operandu moĪemy uĪyü bezpoĞrednio wartoĞci. Na przykáad: BIC r2, r3, #0xFF000000

powoduje wyczyszczenie górnego bajta rejestru r3 i przeniesienie wyniku do rejestru r2.

7.4.2. PRZESUNI}CIA I ROTACJE

7

Na rysunku 7.2 jest pokazana czĊĞü wewnĊtrznej ĞcieĪki danych procesora ARM7TDMI, w której dane dla instrukcji trafiają na dwie magistrale prowadzące do gáównej jednostki arytmetyczno-logicznej. Tylko jedna z tych magistral przechodzi przez cykliczny rejestr przesuwny, który jest dedykowanym blokiem sprzĊtowym pozwalającym na wykonywanie rotacji lub przesuniĊü danych w prawo albo w lewo. Z powodu tej asymetrii moĪemy rotowaü lub przesuwaü tylko jeden operand instrukcji, ale jest to zazwyczaj wystarczające. Przy uĪyciu kilku dodatkowych instrukcji moĪna ominąü to ograniczenie projektowe. W rzeczywistoĞci pomysá umieszczenia cyklicznego rejestru przesuwnego pomiĊdzy bankiem rejestrów (termin opisujący fizyczne rejestry od r0 do r15) a gáównym ALU pozwala na wykorzystanie staáych 32-bitowych w instrukcjach ALU oraz MOV, pomimo Īe sama instrukcja ma wielkoĞü tylko 32 bitów. PokazaliĞmy to w rozdziale 6. na przykáadzie literaáów i staáych.

RYSUNEK 7.2. Cykliczny rejestr przesuwny procesora ARM7TDMI

Typy przesuniĊü i rotacji moĪliwych do wykonania przez procesory ARM są przedstawione na rysunku 7.3. DostĊpne są dwa typy przesuniĊü logicznych, w których dane są traktowane jako liczby bez znaku, przesuniĊcie arytmetyczne, w którym dane są traktowane jako liczby ze znakiem, oraz dwa typy rotacji. Brak rotacji w lewo moĪna wytáumaczyü tym, Īe rotacja w lewo o m bitów jest tym samym co rotacja w prawo o (32–m) bitów (poza efektem ubocznym zmiany bitu przeniesienia), wiĊc moĪe byü realizowana za pomocą tej samej instrukcji. Inną instrukcją, której pozornie brakuje, jest ASL, czyli arytmetyczne przesuniĊcie w lewo. Jednak szybko staje siĊ jasne, Īe nie bĊdziemy nigdy potrzebowaü tej instrukcji, poniewaĪ przesuniĊcia arytmetyczne muszą zachowywaü bit znaku, a przesuniĊcie danych ze znakiem w lewo pozwoli na to, o ile liczba nie ulegnie przepeánieniu. Na przykáad liczba –1 w notacji z dopeánieniem do dwójki ma postaü 0xFFFFFFFF, a po wykonaniu przesuniĊcia w lewo

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

Operacje logiczne i arytmetyczne

113

otrzymujemy 0xFFFFFFFE, czyli –2, co jest prawidáowym wynikiem. Liczba 32-bitowa, na przykáad 0x8000ABCD, przesuniĊta w lewo spowoduje przepeánienie, a w wyniku otrzymamy 0x0001579A, czyli liczbĊ dodatnią.

7

RYSUNEK 7.3. PrzesuniĊcia i rotacje

JeĪeli chcesz przenieĞü dane bez wykonywania dodatkowej operacji, na przykáad dodawania, to naleĪy skorzystaü z MOV. Jak pamiĊtamy z rozdziaáu 6., instrukcja MOV pozwala przesyáaü dane pomiĊdzy rejestrami, wiĊc dodanie opcjonalnej operacji przesuniĊcia pozwala nieco ją rozbudowaü. Przykïad 7.4. Poniĝsze instrukcje ilustrujÈ, jak ïatwo pisze siÚ przesuniÚcia i rotacje. MOV r4, r6, LSL #4 MOV r4, r6, LSL r3 MOV r4, r6, ROR #12

; r4 = r6 b? ; jeĪeli a = b, to koniec ; jeĪeli a < b, to skok ; a = a–b ; skok do początku pĊtli

SUB r1,r1,r0 B gcd

; b = b–a

Bardziej efektywna metoda pomija skok do gaïÚzi, a zamiast tego wykorzystuje warunkowe wykonanie instrukcji: gcd

CMP r0, r1 SUBGT r0, r0, r1 SUBLT r1, r1, r0 BNE gcd

Kod nie tylko wykonuje siÚ szybciej, ale równieĝ zawiera mniej instrukcji. ZwróÊ uwagÚ, ĝe w drugim przypadku kod porównuje dwie liczby, ustawiajÈc znaczniki. Dwie kolejne instrukcje wzajemnie siÚ wykluczajÈ, wiÚc nie wystÈpi przypadek, gdy jedna liczba jest mniejsza i jednoczeĂnie wiÚksza od drugiej. Koñcowy przypadek, kiedy dwie liczby sÈ sobie równe,

Ebookpoint.pl kopia dla: Jaroslaw Biszczuk [email protected]

8

142

Asembler dla procesorów ARM. PodrÚcznik programisty

wymusza zignorowanie obu instrukcji odejmowania, jak równieĝ ostatniej instrukcji skoku. Brak dodatkowych skoków w kodzie ma duĝe znaczenie, poniewaĝ dziÚki temu potok nie jest wielokrotnie opróĝniany przy skokach.

8.6. KODOWANIE W LINII PROSTEJ Teraz gdy pokazaliĞmy, jak usuwaü rozgaáĊzienia w kodzie, moĪemy zadaü sobie pytanie, czy algorytm zawierający pĊtle musi zawieraü instrukcje skoku. OczywiĞcie nie. Okazuje siĊ, Īe w przypadku wielu algorytmów, szczególnie w dziedzinie przetwarzania sygnaáów, zapewnienie maksymalnej szybkoĞci dziaáania jest jednym z najwaĪniejszych zadaĔ przy implementacji. JeĪeli jakiekolwiek opóĨnienia mogą byü usuniĊte z kodu, nawet kosztem zuĪycia pamiĊci, to jest to realizowane. Instrukcje znajdujące siĊ pomiĊdzy początkiem a koĔcem pĊtli moĪna wielokrotnie powtarzaü, a proces ten jest nazywany rozwijaniem pĊtli. Na przykáad jeĪeli mamy wewnątrz pĊtli jedną instrukcjĊ taką jak: Loop

8

MOV MLA SUBS BNE

r1, #10 r3, r2, r4, r5 r1, r1, #1 Loop

; j = 10 ; r3 = r2*r4+r5 ; j = j–1 ; jeĪeli j = 0, to koniec

moĪemy porzuciü pĊtlĊ, powtarzając instrukcjĊ MLA 10 razy. Przypomnij sobie przykáad algorytmu normalizacji prezentowanego na początku tego rozdziaáu: rozgaáĊzienie wymusza usuwanie z potoku instrukcji, które byáy juĪ pobrane i zdekodowane, dlatego procedura moĪe spĊdziü znaczną czĊĞü czasu wykonania na ponownym napeánieniu potoku. Aby tego uniknąü, moĪemy usunąü wszystkie rozgaáĊzienia — procedura moĪe byü znacznie szybsza, ale bĊdzie zajmowaáa wiĊcej pamiĊci z powodu powielenia instrukcji. Procedura normalizacji z podrozdziaáu 8.2 byáa zoptymalizowana przez Symesa (Sloss, Symes i Wright 2004), a wyniki jego pracy są przedstawione poniĪej. Zwróü uwagĊ, Īe liczba cykli dla tej procedury jest staáa — 17 cykli dla ARM7TDMI — dziĊki wykonaniu warunkowemu i brakowi rozgaáĊzieĔ. Instrukcje, które nie są wykonywane i dla których nie są speánione kody warunków, nadal muszą przejĞü przez potok i potrzebują cyklu w fazie wykonania. ; normalizacja na ARM7TDMI ; argument znajduje siĊ w r0 ; liczba przesuniĊü potrzebnych do normalizacji jest zwracana w r1 shift RN r0 x RN r1 AREA Prog8d, CODE, READONLY ENTRY MOV shift, #0 ; shift=0 CMP x, #1
View more...

Comments

Copyright ©2017 KUPDF Inc.
SUPPORT KUPDF