Transcript Open Office

IS1500 Datorteknik o k
Övning CE_O3 – Stackhantering,
subrutiner som anropar subrutiner,
programutveckling
IS1500 Datorteknik o k
DC F1
DC Ö1
DC F2
DC Ö2
CE F1
CE F2
lab dicom
Digitala komponenter
CE Ö1
CE F3
CE Ö2
CE F4
CE Ö3
lab nios2time
CE F5
CE Ö4
hemlab C
CE Ö6
lab nios2io
In- och utmatning
CE F7
CE Ö1
lab nios2int
Avbrott och "trap"
CE F8
CE Ö2
hemlab cache
Cacheminnen
CE F9
CE Ö3
hemlab trådar
Trådar, synkronisering
CE F10
CE Ö10
tentamen
CE F6
CE Ö5
Assemblerprogram
C
Labbar
●
Mycket förberedelser
–
kan ta uppåt en vecka att göra allt
●
Boka labbtid i Daisy
●
lab 1 (nios2time) tar 2 timmar i labbsalen
–
●
ni kan simulera nästan allt på lab 1
Övriga Nios-II-labbar tar 4 timmar i labbet
–
mer hårdvara används. går inte att simulera
Exempel
2.6
●
Subrutin mul10 (repris)
mul10:
●
slli
r10, r4, 3
# R10 ← r4 x 8
●
slli
r11, r4, 1
# R11 ← r4 x 2
●
●
add r2, r10, r11 # summera, lägg i
# returvärdesregistret r2
ret
# retur
Exempel
2.6
●
Anrop till mul10
foo = mul10( 43 ) översätts till följande:
●
movi
r4,43
# R4 ← 43
●
call
mul10
# multiplicera med 10
●
movia r8,foo
# lägg adress till foo i R8
●
stw
# returvärde sparas i foo
r2,0(r8)
Exempel
3.1
Stack
Exempel
3.1
●
●
Stack
Datastruktur
Viktigast:
last in – first out
–
●
●
adress 0
det som adderats sist
måste tas bort först
Hela stacken kan läsas
Bara det senast inlagda
kan tas bort
adress
4 294 967 295
nyast
äldst
Exempel
3.1
●
Stackpekare
Ett register innehåller
adressen till det
senast inlagda värdet
adress 0
adress 0x3fff0
stack pointer
0x3fff0
nyast
äldst
adress 0xffffffff
Exempel
3.1
●
push – inläggning på stack
Steg 1:
minska stackpekarens
värde med 4
–
●
adress 0
så att den pekar ut
nästa lediga plats
ännu nyare
adress 0x3fff0
Steg 2: skriv data
–
på nya platsen
0x3ffec
0x3fff0
inte längre nyast
X
1
adress 0xffffffff
2
äldst
Exempel
3.1
●
●
pop – borttagning från stack
Steg 1: läs värdet
adress 0
Steg 2:
öka stackpekarens
värde med 4
–
det borttagna värdet
skrivs över vid nästa
allokering
1
adress 0x3ffec just nu nyast
blir snart nyast
2 X
0x3fff0
0x3ffec
äldst
adress 0xffffffff
Exempel
3.1
●
●
Makron
.macro PUSH reg
subi sp, sp, 4
stw \reg, 0(sp)
.endm
.macro POP reg
ldw \reg, 0(sp)
addi sp, sp, 4
.endm
●
●
push:
add före store
pop:
load före add
–
Med makron
för push och pop
så blir det rätt överallt
(om man har skrivit
sina makron rätt förstås)
Exempel
3.2
Subrutiner som
anropar subrutiner
Exempel
3.2
Subrutinanrop i flera nivåer
RUT:
ADD …
FKN:
CALL RUT
RET1: ADD …
SUB …
CALL FKN
RETURN
CALL NEW
RETURN
CALL RUT
RET2: SUB ...
Exempel
2.2
●
●
Repris
movia r11,0x471100 # hoppadr till r11
callr r11
# anropa subrutin
programräknarvärdet
skrivs till R31
register
r0 (zero)
r1
...
r11
...
program counter
1. kopiera
pc → R31
r31
Exempel
3.2
●
Returadress på stacken
En subrutin
som anropar
en annan subrutin
måste lägga
sin egen returadress
på stacken
före anropet
adress 0
nyast
äldst
adress 0xffffffff
Exempel
3.2
●
push r31
Steg 1:
minska stackpekarens
värde med 4
–
●
adress 0
så att den pekar ut
nästa lediga plats
2
kopia av r31
adress 0x3fff0
Steg 2: skriv data
–
innehållet i r31
kopieras till
nya platsen
0x3ffec
0x3fff0
inte längre nyast
X
1
adress 0xffffffff
äldst
Exempel
3.2
●
Subrutinstruktur
subrut:
onödigt att pusha och
poppa r31 vid varje call
PUSH ra
...
call some_other_subrut
...
call yet_another_subrut
...
bättre att pusha en gång i början
POP ra
och poppa en gång i slutet
ret
Exempel
3.3
Subrutin med värdeanrop
Exempel
3.3
Subrutin med värdeanrop
●
Summera två heltal
●
Värdeanrop
●
●
Heltalens värden
är parametrar
till subrutinen
call-by-value
●
sumv:
add r2, r4, r5
ret
Exempel
3.4
Huvudprogram
med värdeanrop
Exempel
3.4
●
Huvudprogram
med värdeanrop
int a, b, res;
extern int sumv( int a, int b);
int main()
{
a = 3;
b = 4;
res = sumv(a, b);
return( 0 );
}
Exempel
3.4
●
Assembler
.data
.align 2
a: .word 0
b: .word 0
res: .word 0
.text
# kompilering görs i undermapp
.align 2
.include "../minamacron.s" # därför behövs ../
.global main
main:
PUSH r31
movia r8,a
# adress till variabler
movi r9,3
stw r9,0(r8) # skriv a
movi r9,4
stw r9,4(r8) # skriv b
Exempel
3.4
●
Assembler, fortsättning
ldw
r4,0(r8)
# läs a, lägg i R4
ldw
r5,4(r8)
# läs b, lägg i R5
PUSH r8
call sumv
POP r8
stw
# caller-save r8
# anropa
# restore r8
r2, 8(r8) # skriv returvärdet till variabeln res
movi r2, 0
POP r31
ret
# main ska returnera 0
Exempel
3.4
●
Assembler, fortsättning
ldw
r4,0(r8)
# läs a, lägg i R4
ldw
r5,4(r8)
# läs b, lägg i R5
PUSH r8
call sumv
POP r8
stw
# caller-save r8
# anropa
# restore r8
livslinje (live
range)
för R8
anropet bryter livslinjen
...we must caller-save r8
r2, 8(r8) # skriv returvärdet till variabeln res
movi r2, 0
POP r31
ret
# subrutinen main ska returnera 0
Exempel
1.1
Repris
r16 – r23 får användas
men måste återlämnas
med samma innehåll
Exempel
3.5
Subrutin med referensanrop
Exempel
3.5
Subrutin med referensanrop
●
Summera två heltal
●
Referensanrop
●
●
●
Adresser till minnesceller där heltalen finns
är parametrar till subrutinen
call-by-reference
int suma( int * x, int * y )
{
return *x + *y;
}
Exempel
3.5
●
●
Subrutin med referensanrop
int suma( int * x, int * y )
{
return *x + *y;
}
.global suma
suma:
ldw r8,0(r4)
ldw r9,0(r5)
add r2, r8, r9
ret
adress 0
en adress ena heltalet
en annan adress andra heltalet
adress 0xffffffff
Exempel
3.6
Huvudprogram
med referensanrop
3.6 Huvudprogram med parameteröverföring av adresser i register
Skriv välkommenterad Nios II assemblerkod för ett huvudprogram som använder
subrutinen suma, se föregående uppgift, för att addera två heltal. Nedan visas ett
exempel på hur ett sådant c-program kan se ut.
Handkompilera denna kod till assemblerkod för Nios-II.
int a, b, res;
int suma(int * par1, int * par2);
int main()
{
a = 3;
b = 4;
...
/* annat programarbete
res = suma (&a, &b);
...
return (0);
}
*/
Exempel
3.6
●
Huvudprogram
med referensanrop
int a, b, res;
extern int suma( int * a, int * b);
int main()
{
a = 3;
b = 4;
res = suma( &a, &b);
return( 0 );
}
&a betyder
"adressen där a finns"
Exempel
3.6
●
●
Assembler
.data
a: .word 0
b: .word 0
res: .word 0
.include "../pushpop.s"
.text
.global main
main:
PUSH ra
movia r8,a
movi r9,3
stw r9,0(r8)
movi r9,4
stw r9,4(r8)
hittills är huvudprogrammet
exakt likadant som
versionen med värdeanrop
# adress till variabler
# skriv a
# skriv b
Exempel
3.6
●
Assembler, fortsättning
mov
r4, r8
addi
r5, r8, 4 # lägg adressen till b i R5
PUSH r8
call suma
POP r8
stw
# lägg adressen till a i R4
men inte
nu längre
# caller-save r8
# anropa
# restore r8
r2, 8(r8) # skriv returvärdet till variabeln res
movi r2, 0
POP ra
ret
# main ska returnera 0
Exempel
3.6
Varför referensanrop?
●
Förslag / gissningar / idéer ?
●
Variabler som ska förändras – "sidoeffekter"
●
Värden som inte får plats i ett register
–
textsträngar t ex
Exempel
3.7
Programutveckling
Developing
your
program
C program
text file
#include <file.h>
#include "myfile.c"
include
compile
assembly
program, text file
.include "somefile.s"
include
assemble
machine code
binary file
file.o
link
executable code
binary file
file.elf
load and run
Running
your program
Nios2 CPU
Exempel
3.7
Programutveckling
Skapa nytt projekt...
Exempel
3.7
Programutveckling
1.Ange namn
2.Viktigt! Klicka i
"Specify Location"
3.Viktigt! Välj mall
"Blank Project"
4.PTF-fil: välj
Nios2system20090707.ptf
(från kurswebb)
5.Klicka "Next"
Exempel
3.7
●
Fixa misstag
Ser ni en fil "hello.c" i projektkatalogen
så har ni missat att välja "Blank project"
(enklast: kasta projektet och starta ett nytt)
●
Vid andra fel, kolla i listan "error messages"
http://www.ict.kth.se/courses/IS1200/2009-2010/nios2setup/n2errors.html
●
Fixa alltid
alla fel och
varningar!
Exempel
3.7
Programutveckling
Exempel
3.8
●
●
Minnesdisposition
"Gles" adressrymd
adress 0
ROM
–
mycket ledigt utrymme
adress 0x800 in-/ut-portar
–
vanligt i inbyggda system
adress 0xa20
stackpekaren initieras
av programkod som kör
före "main"
–
ändra ej sp i main
tomt och
oanvändbart
adress 0x800000
minne
adress 0x1000000
adress 0xffffffff
ännu mera
tomt och
oanvändbart
Exempel
3.10
Labb-program
●
int hexasc( int digit );
●
void puttime( int * timeloc );
●
void tick( int * timeloc );
●
void delay( int millisec );
Exempel
3.10
hexasc – kodomvandling
●
0...0 0000 0000 (talet noll) -> 0011 0000 (kod för tecknet "0" på skärmen)
●
0...0 0000 0001 (talet ett) -> 0011 0001 (kod för tecknet "1" på skärmen)
●
...
●
0...0 0000 1001 (talet nio) -> 0011 1001 (kod för tecknet "9" på skärmen)
●
här bryts sekvensen – "A" kommer inte närmast efter "9" i ASCII-tabellen
●
0...0 0000 1010 (talet tio) -> 0100 0001 (kod för tecknet "A" på skärmen)
●
0...0 0000 1011 (talet elva) -> 0100 0010 (kod för tecknet "B" på skärmen)
●
...
●
0...0 0000 1111 (talet femton) -> 0100 0110 (kod för tecknet "F" på skärmen)
Exempel
3.10
●
Lagring av tids-info (2 byte)
Byte på adress timeloc:
adress 0
0 1 0 1 0 1 1 1
5
●
två 4-bitars sekundsiffror
–
●
7
varje siffra kan vara 0–9
adress timeloc 0x57
0x17
Byte på adress timeloc+1:
0
0
0 0 0 1 0 1 1 1
1
●
7
två 4-bitars minutsiffror
adress 0xffffffff
Exempel
3.10
●
tick – räkna upp tiden 1 sekund
Byte på adress timeloc:
0 1 0 1 0 1 1 1
5
●
7
addera 1:
+ 1
0 1 0 1 1 0 0 0
5
●
8
Vad händer när man kommer till 59 ?
Exempel
3.10
●
tick
Byte på adress timeloc:
0 1 0 1 1 0 0 1
5
●
9
addera 1:
+ 1
0 1 0 1 1 0 1 0
5
●
10 = FEL
Kolla om det blev fel, rätta till i så fall
Exempel
3.10
●
tick
Uppräknat genom addition med 1:
anta att värdet finns i R8
0 1 0 1 1 0 1 0
5
●
andi
10 = FEL
r9, r8, 0xf
... 0 0 0 1 1 1 1
0 0 0 0 1 0 1 0
att fundera på: varför blir
det rätt när vi adderar 6?
●
movi
bne
addi
fram:
r10, 0xa
r9, r10, fram
r8, r8, 6
Exempel
3.11
●
Biblioteksrutiner
putchar
–
ett argument, ett returvärde
–
ett tecken i r4, tecknet sänds ut på jtag_uart som
är kopplad till textfönstret Console i Nios II IDE
–
returvärde i r2, statusinformation
–
om allt gick bra så returneras samma tecken
som skickades
Exempel
3.12
Fördröjningsrutin
Exempel
3.12
Fördröjningsrutin
●
Wait ska ta 100 ms = 5 000 000 klockcykler
●
1 cykel/instruktion: kör 5 000 000 instruktioner
●
bgt tar 2 cykler när bakåthoppet tas
●
3 cykler/varv, kör 5 000 000 / 3 varv
●
wait:
movia
r8,1666666
●
wloop:
subi
bgt
r8,r8,1
r8,r0,wloop
●
ret
Exempel
3.13
Varierbar fördröjningsrutin
Exempel
3.13
Varierbar fördröjningsrutin
●
WAITX tar n x 100 ms, anropa wait n gånger
●
waitx:
●
●
●
ble
r4,r0,nowait
PUSH
PUSH
call
POP
POP
r4
r31
wait
r31
r4
subi
br
r4,r4,1
waitx
nowait: ret
Exempel
3.13
Kompilerad fördröjningsrutin
●
wait:
bge
r0,r4,nowait
●
oloop:
addi
r4,r4,-1
movi
r2,4711
addi
r2,r2,-1
●
blt
r0,r2,iloop
●
blt
r0,r4,oloop
●
nowait: ret
●
●
iloop:
Exempel
3.14
Assemblerdirektiv
●
.include "fil.ext"
# infogar fil.ext
●
.data
# placera i data-area
●
.text
# placera i text-area/code-area
●
.global name
# name blir globalt synlig (exporteras)
●
.align 1
# next address is a multiple of 2
●
.align 2
# next address is a multiple of 4
●
.align 3
# next address is a multiple of 8
●
.align 4
# next address is a multiple of 16
●
# .align specification varies
●
# sometimes it means number of low-order zero bits (i386 a.out-format)
Exempel
3.14
Assemblerdirektiv
●
TAL:
.byte 0x01
# reserve one byte with value 0x01
●
ADR: .word 0x12AB
# reserve one word with value 0x12AB
●
.equ
const, 17
# define symbolic name of const
●
.equ
statusaddr, 0xff2300 # define symbolic name of statusaddr
●
Hello: .ascii "Hello World" # text lagras som ASCII-code
●
Hello: .asciz "Hello World" # text lagras som null-terminated ASCII-code
●
Hello: .string "Hello World" # text lagras som null-terminated ASCII-code