Ziele:
Verständnis für LOAD und STORE Befehle, bedingte Befehle und die verschiedenen Speicherbereiche. Ziel ist die Implementierung mit möglichst geringer Codegröße sowie der Umgang mit einem Debugger/Simulator und der Entwicklungsumgebung.
Arbeitsverzeichnis:
Kopieren Sie sich das Verzeichnis, welches Ihnen im Praktikum zur Verfügung gestellt wird, in Ihr persönliches Verzeichnis. Dort stehen Ihnen dann alle benötigten Dateien zur Verfügung.
Vorbereitung
Arbeiten Sie sich in folgende Befehle des ARM-Prozessors ein:
Instruktion := Bedeutung
ADDNE R1, R2, #1 R1 := R2 + 1, falls das Z-Bit im Prozessorstatuswort nicht gesetzt ist
LDR R1, [R2] R1 := mem32[R2]
LDREQ R1, [R2] R1 := mem32[R2], falls das Z-Bit im Prozessorstatuswort gesetzt ist
LDRB R1, [R2] R1 := mem8[R2]
STR R1, [R2] mem32[R2] := R1
STRB R1, [R2] mem8[R2] := R1
ADR R1, Marke R1:=PC+(Offset zur Marke)
B Marke PC wird auf Adresse der Marke gesetzt
BEQ Marke PC wird auf Adresse der Marke gesetzt, falls das Z-Bit im Prozessorstatuswort gesetzt ist
BNE Marke PC wird auf Adresse der Marke gesetzt, falls das Z-Bit imProzessorstatuswort nicht gesetzt ist
Aufgabe 1:
.file "aufgabe1.S"
.text @ legt eine Textsection fuer PrgrammCode + Konstanten an
.align 2 @ sorgt dafuer, dass nachfolgende Anweisungen auf einer durch 4 teilbaren Adresse liegen
@ unteren 2 Bit sind 0
.global main @ nimmt das Symbol main in die globale Sysmboltabelle auf
.type main,function
main:
// Hier bitte Ihren ProgrammCode einfuegen
mov r0, #0 // r0=0x0; r1=0x1ffff8 zu diesem Zeitpunkt
str r1, [r0], #4 // Inhalt von r1 auf Adresse 0x00000000. Danach steht in r0 0x4
eor r0, r0, r0 // r0=0x0
str r1, [r0, #4] // Inhalt von r1 auf Adresse 0x00000004, danach steht in r0 0x0
mov r0, #0 // r0=0x0
str r1, [r0]! // Inhalt von r1 auf Adresse 0x00000000, danach steht in r0 0x0
sub r0, r0, r0 // r0=0x0
str r1, [r0, #4]! // Inhalt von r1 auf Adresse 0x00000004, danach steht in r0 0x4
and r0, r0, #0 // r0=0x0
strb r1, [r0, #1]! // Inhalt von r1 auf Adresse 0x00000001 (nur hintere 8bit), danach steht in r0 0x1
mov r1, #4 // r1=0x4
strb r1, [r0, r1]! // Inhalt von r1 auf Adresse 0x00000005 (nur hintere 8 bit), danach steht in r0 0x5
bx lr
.Lfe1:
.size main,.Lfe1-main
// End of File
Aufgabe 2:
Bearbeiten Sie schriftlich die Zusatzfragen.
a) Auf welche Weise kann man die Condition-Code-Flags NZCV (Bedingungsbits) des Prozessorstatuswort (CPSR) setzen?
Lösung: Indem man an die ARM-Befehle ein „S“ anhängt (z.B. ADDS, SUBS …) oder die Befehle TST, TEQ, CMP oder CMN verwendet.
b) Wie wird die Pseudoinstruktion “ADR R1, Marke” vom Assembler umgesetzt? Schreiben Sie hierzu den Befehl in einen der vorgegebenen Programmrahmen und schauen Sie ihn sich im Debugger in der Mixed-Darstellung an (rechts oben Source auswählen). → Vollziehen Sie die Umsetzung des Compiler nach und informieren Sie sich auch über Pipelining.
Lösung
Ein Befehl kann in einem Zyklus gefetched werden. Wird er im nächsten Zyklus decoded, kann man bereits im selben Zyklus den nächsten Befehl fetchen. ADR wird entweder in ein ADD oder SUB umgesetzt, da ADR eigentlich keine Instruktion ist.
In diesem Fall erzeugt ADR diesen Befehl:
ADD r1, PC, 0x8
- PC steht für den Wert, nachdem das ADR ausgeführt wurde (somit nochmals um 8 erhöht wurde).
- 0x8 steht für die Distanz zu Marke vom PC, (4x Anzahl der Befehle zwischen PC und Marke)
Programm Aufgabe2
.file "aufgabe2.S"
.text @ legt eine Textsection fuer PrgrammCode + Konstanten an
.align 2 @ sorgt dafuer, dass nachfolgende Anweisungen auf einer durch 4 teilbaren Adresse liegen
@ unteren 2 Bit sind 0
.global main @ nimmt das Symbol main in die globale Sysmboltabelle auf
.type main,function
main:
ADR r1, Marke // PC+0 = Fetch von ADR
mov r0,#0 // PC+4 = Decode von ADR
mov r0,#1 // PC +8 = Execute von ADR
mov r0,#2 // Execute +4
Marke: .word 0x00000000 // Execute +8
.Lfe1:
.size main,.Lfe1-main
// End of File
c) Das Prozessorstatuswort hat den Wert 0xa00013, wenn der Befehl “BNE Marke” ausgeführt wird. Würde dann der Sprung an die (symbolische) Adresse Marke ausgeführt? Weisen Sie Ihre Antwort mit einem Programm nach.
Lösung: Ja, da BNE bedeutet, dass etwas ausgeführt wird, wenn das Zero-Bit nicht gesetzt ist. Zum Zeitpunkt des Befehls steht im CPSR 0x00a00013, somit ist das Zero-Bit 0 und der Sprung wird ausgeführt.
Aufgabe 3:
Es ist ein Programm zu entwickeln, welches alle Werte einer Liste1 nach Liste2 kopiert. In den Listen steht an erster Stelle die Anzahl der Elemente der jeweiligen Liste. Liste1 ist, bis auf die erste Zahl (Anzahl der Elemente max. 255) eine Liste mit 8Bit großen vorzeichenbehafteten Zahlen (-128 bis +127). In Liste2 sollen die Zahlen aus Liste1, ausser die Anzahl der Elemente (die bleibt vorzeichelos), als 32Bit große vorzeichenbehaftete Zahlen abgelegt werden.
Lösung
- 8 Bit Zahlen in Register laden
- Zahlen mit 24 Bit Verschiebung in den Speicher schreiben
- Vorzeichenwechsel mit ASR erzeugen (Laden, Verschieben, ASR mit 0/1 auffüllen lassen)
Aufgabe 4:
Nach dem Kopiervorgang soll in einem weiteren Schritt die Liste2 aufsteigend sortiert werden. Hierzu erweitern Sie Ihr Programm von Aufgabe 3. Es gibt verschiedene Sortieralgorithmen (z.B. Bubblesort). Denken Sie daran, dass die Länge der Liste an erster Stelle stehen bleiben muss.
Lösung
.file "aufgabe3.S"
.text @ legt eine Textsection fuer PrgrammCode + Konstanten an
.align 2 @ sorgt dafuer, dass nachfolgende Anweisungen auf einer durch 4 teilbaren Adresse liegen
@ unteren 2 Bit sind 0
.global main @ nimmt das Symbol main in die globale Sysmboltabelle auf
.type main,function
main:
stmfd sp!, {r4, r5, lr} @ Ruecksprungadresse und Register sichern
kopieren:
@ hier Ihr Programm zum Kopieren einer Byte-Tabelle (je 8Bit) in eine Word-Tabelle (je 32Bit) einfuegen
LDR r1, =Liste1 // Position von Liste1 bestimmen
ADR r2, TAB2 // Position von TAB2 bestimmen
LDR r2, [r2] // Position der Werte für Tab2 bestimmten
LDRb r3, [r1] // Zähler für Loop
loop0: // Schleife für Einlesen der Werte
LDRB r0, [r1], #1 // Nächstes Element einlesen (8 Bit Zahl)
vorzeichen:
MOV r0, r0, LSL #24
MOV r0, r0, ASR #24
// Bereich für Speichern der Liste
STR r0, [r2], #4 // Wert von r0 nach Liste2 speichern
sub r3, r3, #1 // Dekrementierung des "loop0"-Counters um 1
CMP r3, #0 // Vergleich ob r3-0=0 und Statusbits setzen
BNE loop0 // Sprung zu loop0, wenn r3 nicht null war
BEQ sortieren // Aufruf der "Sortieren"-Funktion, wenn r3 null war
sortieren: // hier Ihr Programm um die vorzeichenrichtige Zahlen in Liste2 zu sortieren
ADR r0, TAB2 // Position von TAB2 bestimmen
LDR r0, [r0] // Position der Werte von TAB2 bestimmen (r0 ist die Laufvariable)
LDR r3, [r0],#4 // Zähler (1. Element) für Schleifen laden und auf nächstes Element setzen
sub r3,r3,#2 // Zähler um 2 dekrementieren
mov r6,r0 // r0 nach r6 sichern
mov r1, r3 // Zähler für die äußere Schleife setzen
loop1: // Funktion der äußeren Schleife
mov r0,r6 // r0 auf die Position der Tabelle2 setzen
mov r2, r3 // Innere Schleife zurücksetzen
loop2: // Funktion für die innere Schleife
sub r2,r2,#1 // Zähler der inneren Schleife um 1 dekrementieren
LDR r4,[r0] // Aktuelles Element laden nach r4
LDR r5,[r0,#4]! // Folgendes Element laden nach r5
cmp r4,r5 // Vergleich: r4-r5
STRGT r5,[r0,#-4] // Speichern von r5 an die Position von r4
STRGT r4,[r0] // Speichern von r4 an die Position von r5
cmp r2,#0 // Vergleich: r2-0
bne loop2 // Aufruf der inneren Schleife, wenn r2 nicht null ist
sub r1, r1,#1 // Zähler der äußeren Schleife um 1 dekrementieren
cmp r1,#0 // Vergleich r1-0
bne loop1 // Aufruf der äußeren Schleife, wenn r1 nicht null ist
beq fertig // Ende des Sortierens und Aufruf von "fertig", wenn r1 null ist.
fertig:
ldmfd sp!, {r4, r5, pc} @ Ruecksprungadresse und Register
TAB2: .word Liste2 @ Beispiel um an Adressen aus anderen Segmenten zu kommen
.Lfe1:
.size main,.Lfe1-main
// .data-Section fuer initialisierte Daten
.data
// Erster Wert der Tabelle steht fuer die Anzahl (max. 64) der Werte der Tabelle
Liste1: .byte (Liste1Ende-Liste1), -7, 8, -9, 6, -5, 4, -3, 2, -1, 0, 127, 128 //128
Liste1Ende:
// .comm-Section fuer nicht initialisierte Daten
.comm Liste2, ((Liste1Ende-Liste1)*4) @ Speicherbereich mit der Groesse*4 von Liste1 reservieren
// End of File
Bericht
Der erforderliche Praktikumsbericht dient zu Ihrer Nachbereitung des Praktikums und wird stichprobenhaft überprüft. Er beinahltet auch den zeilenweisen kommentierten Quelltext. Haben Sie Ihre Berichte zu den Praktikumsterminen dabei.