Escolar Documentos
Profissional Documentos
Cultura Documentos
programação Assembly
Cap. 2: “Instructions: Language of the Computer”
Compilação e execução de código
Visão geral
O interface entre software e hardware
Aplicação
(linguagem de alto nível) Arquitetura de conjunto de instruções
ou
Instruction Set Architecture (ISA)
▪ Sistema operativo:
▫ Gestão das entradas e saídas
▪ Hardware:
▫ Processador, memória, controladores I/O
4
Instruction Set Architecture (ISA)
2. Define os operandos
▫ Registos (ex: R0,…R31),
▫ Memória,
▫ Imediato (ao nível do ISA denomina-se por imediato quando um operando toma um valor constante)
5
Instruction Set Architecture (ISA)
RISC-V
Programação Assembly
Como aprender?
7 7
Instruction Set Architecture (ISA)
RISC-V
8
Instruction Set Architecture (ISA)
RISC-V
▫ O RISC-V contém
▫ 32 registos de inteiros (x0,x1,…,x31).
▫ Dependendo da implementação, os registos podem ser de 32 ou 64 bits
▫ O registo x0 vale sempre 0 (mesmo após uma escrita para este registo)
9 9
Instruction Set Architecture (ISA)
RISC-V
10 10
Instruction Set Architecture (ISA)
RISC-V
▫ Base:
▫ RV32I – Operações sobre inteiros (I), registos de 32 bits
▫ RV32E – Operações sobre inteiros (I), registos de 32 bits, versão reduzida para sistemas embebidos
▫ RV64I – Operações sobre inteiros (I), registos de 64 bits
▫ RV128I – Operações sobre inteiros (I), registos de 128 bits
▫ Extensões (não exaustivo):
▫ M – Operações de multiplicação e divisão sobre inteiros
▫ A – Operações Atómicas
▫ F – Operações de virgula flutuante, precisão simples (C float)
▫ D – Operações de virgula flutuante, precisão dupla (C double)
▫ C – Instruções comprimidas (16-bits)
▫ V – Operações vetoriais
▫ Conjunto típico
▫ RV32G “Geral”: RV32I + M + A + F + D
▫ RV64G “Geral”: RV64I + M + A + F + D
11 11
Instruction Set Architecture (ISA)
RISC-V
Nota: Não é necessário decorar as instruções. Para o laboratório e para o teste será disponibilizado uma folha de referência com o
conjunto de instruções.
12 12
Instruction Set Architecture (ISA)
RISC-V
13 13
Instruction Set Architecture (ISA)
RISC-V
Registos inteiros
Directives de Assembly
14 14
Instruction Set Architecture (ISA)
RISC-V
15 15
Instruction Set Architecture (ISA)
RISC-V
Instruções
Não é para decorar, é para consultar sempre que necessário
16 16
Instruction Set Architecture (ISA)
RISC-V
Classe da instrução
17 17
Instruction Set Architecture (ISA)
RISC-V
Mnemónica e operandos
18 18
Instruction Set Architecture (ISA)
RISC-V
Nome da instrução
19 19
Instruction Set Architecture (ISA)
RISC-V
Descrição em RTL
(Register Transfer Level)
20 20
Instruction Set Architecture (ISA)
RISC-V
Campos da codificação
(conjugar com a tabela do formato)
21 21
Instruções do tipo
RV32IM
22
Instruções do tipo
RV32IM
Pseudo-instruções
Não são instruções de facto,
mas realizam-se à custa
de 1 ou mais instruções reais
23
Instruções do tipo
RV32IM
Operações aritméticas,
lógicas e de deslocamento
24
Instruções do tipo
RV32IM
Multiplicação
e divisão
25
Instruções do tipo
RV32IM
Transferência
26
Instruções do tipo
RV32IM
lui xd,imm
S = Single D = Double
29 (C float) (C double)
Exemplo
Cálculo de um polinómio
#define a0 5
#define a1 7 Realize a operação:
#define a2 -5
𝑦 = 𝑎0 + 𝑎1 × 𝑥 − 𝑎2 × 𝑥 2
int x, y;
…
y = a0 + a1*x + a2*x*x; onde 𝑎0 , 𝑎1 e 𝑎2 são constantes.
30
Exemplo
Cálculo de um polinómio
# x5=x, x6=y
li x6,5 # y = a0
li x7,7 # a1=7
mul x7,x7,x5
add x6,x6,x7 # y = a0 + a1*x
li x7,-5 # a2=-5
mul x7,x7,x5
mul x7,x7,x5
add x6,x6,x7 # y = a0 + a1*x + a2*x*x
31
Exemplo
Cálculo de um polinómio
# x5=x, x6=y
li é uma pseudo-instrução.
li x6,5 # y = a0
Como em todos os casos o
imediato (constante) é
li x7,7 representável com menos de 12
mul x7,x7,x5 bits, poderiamos, em alternativa
add x6,x6,x7 # y = a0 + a1*x usar
addi xd,x0,imm
li x7,-5
mul x7,x7,x5 ou
mul x7,x7,x5
add x6,x6,x7 # y = a0 + a1*x + a2*x*x ori xd,x0,imm
32
Exemplo
Cálculo de um polinómio
li x7,7
mul x7,x7,x5
addi x6,x7,5 # y = a0 + a1*x
li x7,-5
mul x7,x7,x5
mul x7,x7,x5
add x6,x6,x7 # y = a0 + a1*x + a2*x*x
33
Exemplo
Cálculo de um polinómio
34
Exemplo
Cálculo de um polinómio
li x5,-5
fcvt.s.w f2,x5 # f2 = (float) a2
Todas as instruções em FP têm o
fmul.s f2,f0,f2 # f2 = ((float) a2)*x
sufixo “.s”, que representa precisão
fmul.s f2,f0,f2 # f2 = ((float) a2)*x*x simples (float). Se fosse precisão
fadd.s f1,f1,f2 # y = a0 + a1*x + a2*x*x dupla (double) usar-se-ia o prefixo “.d”
35
Exemplo
Cálculo de um polinómio
li x5,7
fcvt.s.w f2,x5 # f2 = (float) a1
fmul.s f2,f0,f2 # f2 = ((float) a1)*x
Podemos usar a operação
fadd.s f1,f1,f2 # y = a0 + a1*x
fused fmadd.s
li x5,-5
fcvt.s.w f2,x5 # f2 = (float) a2
fmul.s f2,f0,f2 # f2 = ((float) a2)*x
fmul.s f2,f0,f2 # f2 = ((float) a2)*x*x
fadd.s f1,f1,f2 # y = a0 + a1*x + a2*x*x
36
Exemplo
Cálculo de um polinómio
li x5,7
fcvt.s.w f2,x5 # f2 = (float) a1
fmadd.s f1,f2,f0,f1 # y = a1*x + a0
li x5,-5
fcvt.s.w f2,x5 # f2 = (float) a2
fmul.s f2,f0,f2 # f2 = ((float) a2)*x
fmadd.s f1,f2,f0,f1 # y = (a2*x)*x + (a1*x + a0)
f2 f0 f1
37
Exemplo
Cálculo de um polinómio
#define a0 5.0
#define a1 7.0 Mas geralmente as variáveis estão
#define a2 -5.0 guardadas em memória e não em
registos!
float x, y;
…
y = a0 + a1*x + a2*x*x; Como aceder à memória?
38
Instruction Set Architecture (ISA)
RISC-V
→ Instruções de acesso à memória
Estrutura lógica do core
Memória
Core
Registos
Data
inteiros
(X0,…,X31) ALU Address
(Arithmetic and Dados
Registos Logic Unit)
FP Size
(F0,…,F31)
(byte/halfword/word/doubleword) Instruções
Existem dois bancos de registos: Existe uma única memória com dados e instruções:
• X0…X31 (inteiros) • Do ponto de vista lógico segue o Modelo de Von Neumann
• F0…F31 (floating point) • Veremos mais à frente que, do ponto de vista físico, segue
40 um modelo Harvard Modificado
RISC-V Instruction Set Architecture (ISA)
Definição de “load” e “store”
SP FP float 4B 4
DP FP double 8B 8
42
RISC-V Instruction Set Architecture (ISA)
Dimensão das palavras na memória
Endereço na memória, soma do imediato de 12 bits (com sinal) com o valor no registo xb
Registo origem/destino
Instrução RTL
Variantes:
Tipo (C) Dimensão Instruções
lb / lbu
char / byte 8 bits lb, lbu, sb
Quando carregado para um
registo (X0,…,X31), o valor lido
da memória é estendido:
• lbu: com zeros
• lb: com o sinal
Instrução RTL
Variantes:
Tipo (C) Dimensão Instruções
Lx / LxU
char / byte 8 bits lb, lbu, sb
Quando carregado para um
short 16 bits lh, lhu, sh registo (X0,…,X31), o valor lido
da memória é estendido:
int / long 32 bits lw, lwu, sw • LxU: com zeros
• Lx: com o sinal
long long 64 bits ld, sd
Instrução RTL
48
Lista1=100h ➔ {-1127,+3401,1457,-4832}
Lista2=200h ➔ {…}
Exemplo: …
Cópia de uma 10Fh
10Ch
Considere uma lista de 10Bh
palavras (32 bits), 10Ah
+1457
armazenada em memória. 109h
Escreva o código que 108h
copia os 4 elementos para 107h
106h
a zona de outra lista de +3401
105h
valores. 104h
103h
102h
-1127
101h
100h
49 …
Lista1=100h ➔ {-1127,+3401,1457,-4832}
Lista2=200h ➔ {…}
Exemplo: …
la x10,lista1
Cópia de uma 10Fh
la x11,lista2
lista de valores 10Eh
10Dh
-4832
10Ch
Considere uma lista de 10Bh
palavras (32 bits), 10Ah
+1457
armazenada em memória. 109h
Escreva o código que 108h
copia os 4 elementos para 107h
106h
a zona de outra lista de Inicialização dos registos x10 e x11 com o +3401
105h
valores. endereço das listas de valores. 104h
103h
102h
Na prática diz-se que x10 e x11 são ponteiros -1127
101h
para Lista1 e Lista2 (i.e., guardam o endereço
do primeiro elemento da lista) 100h
50 …
Lista1=100h ➔ {-1127,+3401,1457,-4832}
Lista2=200h ➔ {…}
Exemplo: …
la x10,lista1
Cópia de uma 10Fh
la x11,lista2
lista de valores 10Eh
10Dh
-4832
10Ch
Considere uma lista de lw x12,0(x10)
10Bh
palavras (32 bits), sw x12,0(x11) 10Ah
+1457
armazenada em memória. 109h
Escreva o código que lw x12,4(x10) 108h
copia os 4 elementos para sw x12,4(x11) 107h
106h
a zona de outra lista de +3401
105h
valores. lw x12,8(x10)
104h
sw x12,8(x11) 103h
102h
-1127
lw x12,12(x10) 101h
100h
sw x12,12(x11)
51 …
Informativo
…
▪ Determine o valor de cada byte 10Fh
em memória 10Eh
-4832
10Dh
10Ch
10Bh
10Ah
+1457
109h
108h
107h
106h
+3401
105h
104h
103h
102h
-1127
101h
100h
52 …
Informativo
Valores armazenados em cada posição de memória
…
▪ Determine o valor de cada byte 10Fh
em memória FF FF ED 20h
10Eh
-4832
10Dh
10Ch
10Bh
10Ah
00 00 05 B1h +1457
109h
108h
107h
106h
00 00 0D 49h +3401
105h
104h
103h
102h
FF FF FB 99h -1127
101h
100h
53 53 …
Informativo
Valores armazenados em cada posição de memória
… …
▪ Determine o valor de cada byte 10Fh 10Fh
em memória 10Eh
FF FF ED 20h
10Eh
-4832
10Dh 10Dh
10Ch 10Ch
10Bh 10Bh
10Ah 10Ah
00 00 05 B1h +1457
109h 109h
108h 108h
107h 107h
106h 106h
00 00 0D 49h +3401
105h 105h
104h 104h
103h 103h
102h 102h
FF FF FB 99h -1127
101h 101h
100h 100h
54 54 … …
Informativo
Valores armazenados em cada posição de memória
… …
▪ Determine o valor de cada byte 10Fh FFh 10Fh
em memória 10Eh FFh
FF FF ED 20h
10Eh
-4832
10Dh EDh 10Dh
10Ch 20h 10Ch
▪ A organização dos bytes em 10Bh 00h 10Bh
… … … …
000Fh Byte 15 000Fh Half-Word 000Fh 000Fh
7 Word 3
000Eh Byte 14 000Eh 000Eh 000Eh
/
000Dh Byte 13 000Dh Half-Word 000Dh 000Dh Double
SP FP 3
000Ch Byte 12 000Ch 6 000Ch 000Ch Word 1
000Bh Byte 11 000Bh Half-Word 000Bh 000Bh /
5 Word 2 DP FP 1
000Ah Byte 10 000Ah 000Ah 000Ah
/
0009h Byte 9 0009h Half-Word 0009h 0009h
SP FP 2
0008h Byte 8 0008h 4 0008h 0008h
0007h Byte 7 0007h Half-Word 0007h 0007h
3 Word 1
0006h Byte 6 0006h 0006h 0006h
/
0005h Byte 5 0005h Half-Word 0005h 0005h Double
SP FP 1
0004h Byte 4 0004h 2 0004h 0004h Word 0
0003h Byte 3 0003h Half-Word 0003h 0003h /
1 Word 0 DP FP 0
0002h Byte 2 0002h 0002h 0002h
/
0001h Byte 1 0001h Half-Word 0001h 0001h
SP FP 0
0000h Byte 0 0000h 0 0000h 0000h
56
RISC-V Instruction Set Architecture (ISA)
Dimensão das palavras na memória
Directiva Descrição
.text Declara uma zona de código (instruções)
.data Declara uma zona de dados writable
Directiva Descrição
.zero N Declara um vetor de N bytes inicializados a 0
Declara um vetor de bytes (1B) sequenciais em memória com valores
.byte num1 [,num2, …]
num1, [num2, …]
.half num1 [,num2, …] Declara um vetor de half (2B) sequenciais em memória
.word num1 [,num2, …] Declara um vetor de words (4B) sequenciais em memória
.dword num1 [,num2, …] Declara um vetor de doublewords (8B) sequenciais em memória
.string “list of characters” Declara uma string em memória. Cada character (char) ocupa 1 B
62
Definem-se duas “zonas” no código Assembly: dados e
código.
# Código
.text
la x1,var1
lw x2,0(x1)
loop: j loop
63
Definem-se duas “zonas” no código Assembly: dados e
código.
Valores em
Ripes # Declaração de variáveis hexadecimal
Simulador .data (nomenclatura
var1: .word 153 de C)
Estrutura de um var2: .half -1227, 3443,213,0x14,13
programa em str1: .string “cadeia de caracteres”
Assembly
# Código
.text
la x1,var1
lw x2,0(x1)
loop: j loop
64
Definem-se duas “zonas” no código Assembly: dados e
código.
# Código
.text
la x1,var1
lw x2,0(x1)
loop: j loop
65
Definem-se duas “zonas” no código Assembly: dados e
código.
# Código
.text Instruções
la x1,var1
lw x2,0(x1)
loop: j loop
66
Definem-se duas “zonas” no código Assembly: dados e
código.
# Código
.text
la x1,var1
lw x2,0(x1)
loop: j loop
67
Instruction Set Architecture (ISA)
RISC-V
→ Controlo do fluxo de instruções
Revisão da estrutura lógica do core
Core Memória
Registos
inteiros
(X0,…,X31) ALU Data
(Arithmetic and
Registos Logic Unit) Dados
FP Address
(F0,…,F31)
Instruções
Registos especiais (ex: PC)
Existem dois bancos de registos: Existe uma única memória com dados e instruções:
• X0…X31 (inteiros) • Do ponto de vista lógico segue o Modelo de Von Neumann
• F0…F31 (floating point) • Veremos mais à frente que, do ponto de vista físico, segue
69 um modelo Harvard Modificado
Fluxo de instruções
la x10,lista1
▪ Exemplo da última aula (cópia dos
la x11,lista2
elementos de um vetor A para outro
vetor B)
Ordem de execução
lw x12,0(x10)
das instruções
sw x12,0(x11)
lw x12,4(x10)
sw x12,4(x11)
lw x12,8(x10)
sw x12,8(x11)
lw x12,12(x10)
sw x12,12(x11)
70
Fluxo de instruções
la x10,lista1
▪ Exemplo da última aula (cópia dos
la x11,lista2
elementos de um vetor A para outro
vetor B)
Ordem de execução
lw x12,0(x10)
das instruções
sw x12,0(x11)
08h: lw x12,0(x10)
0Ch: sw x12,0(x11)
10h: lw x12,4(x10)
14h: sw x12,4(x11)
18h: lw x12,8(x10)
1Ch: sw x12,8(x11)
20h: lw x12,12(x10)
73 24h: sw x12,12(x11)
Fluxo de instruções
Endereço na
memória Instrução
▪ Por omissão as instruções são
executadas em sequência. 00h: ori x10,x0,100h
04h: ori x11,x0,200h
Ordem de execução
instrução se encontra, existe um registo 0Ch: sw x12,0(x11)
das instruções
que contém o endereço da instrução a
executar: 10h: lw x12,4(x10)
14h: sw x12,4(x11)
Program counter (PC)
18h: lw x12,8(x10)
▪ O nome mais adequado para este registo 1Ch: sw x12,8(x11)
seria Instruction Address Register, mas o
nome é histórico. 20h: lw x12,12(x10)
74 24h: sw x12,12(x11)
Fluxo de instruções
Execução de um troço de código
Xn
X0
X1 Banco de
X2 registos para
inteiros
……
X31
double
Data
Single
F0
F1
Banco de registos para
…
vírgula flutuante Program
F31
75
Fluxo de instruções
Execução de um troço de código
… …
X0 0 ?
PC 0000 0000h 0204h
…
?
0200h
X10
… …
X11 +3401
0104h
X12
-1127
… 0100h
… …
X31
sw x12,4(x11)
0014h
lw x12,4(x10)
0010h
F0
sw x12,0(x11)
F1 000Ch
Ponto inicial:
… lw x12,0(x10)
Quando se faz reset ao processador coloca-se o PC=0, 0008h
F31 obrigando a executar a instrução armazenada na ori x11,x0,200h
0004h
posição 0 PC
76 ori x10,x0,100h
0000h
Fluxo de instruções
Execução de um troço de código
… …
X0 0 ?
PC 0000 0004h 0204h
…
?
0200h
X10 0000 0100h
… …
X11 +3401
0104h
X12
-1127
… 0100h
… …
X31
sw x12,4(x11)
0014h
lw x12,4(x10)
0010h
F0
sw x12,0(x11)
F1 000Ch
Resultado da execução da primeira instrução:
… lw x12,0(x10)
Como cada instrução ocupa 4 bytes, o registo PC é 0008h
F31 incrementado por 4 de cada vez que uma instrução é PC ori x11,x0,200h
0004h
executada
77 ori x10,x0,100h
0000h
Fluxo de instruções
Execução de um troço de código
… …
X0 0 ?
PC 0000 0008h 0204h
…
?
0200h
X10 0000 0100h
… …
X11 0000 0200h +3401
0104h
X12
-1127
… 0100h
… …
X31
sw x12,4(x11)
0014h
lw x12,4(x10)
0010h
F0
sw x12,0(x11)
F1 000Ch
Resultado da execução da segunda instrução:
… PC lw x12,0(x10)
Na prática, sempre que uma instrução é executada, o 0008h
F31 PC tem necessariamente de ser alterado. ori x11,x0,200h
0004h
78 ori x10,x0,100h
0000h
Fluxo de instruções
Execução de um troço de código
… …
X0 0 ?
PC 0000 000Ch 0204h
…
?
0200h
X10 0000 0100h
… …
X11 0000 0200h +3401
0104h
X12 FFFF FB99h (-1127)
-1127
… 0100h
… …
X31
sw x12,4(x11)
0014h
lw x12,4(x10)
0010h
F0
PC sw x12,0(x11)
F1 000Ch
Na prática pode-se dizer que o PC é um ponteiro, que
aponta
… (guarda o endereço) para a próxima instrução lw x12,0(x10)
0008h
F31 a executar. ori x11,x0,200h
0004h
79 ori x10,x0,100h
0000h
Fluxo de instruções
Execução de um troço de código
… …
X0 0 ?
PC 0000 0010h 0204h
…
-1127
0200h
X10 0000 0100h
… …
X11 0000 0200h +3401
0104h
X12 FFFF FB99h
-1127
… 0100h
… …
X31
sw x12,4(x11)
0014h
PC lw x12,4(x10)
0010h
F0
sw x12,0(x11)
F1 000Ch
Na prática pode-se dizer que o PC é um ponteiro, que
aponta
… (guarda o endereço) para a próxima instrução lw x12,0(x10)
0008h
F31 a executar. ori x11,x0,200h
0004h
80 ori x10,x0,100h
0000h
Fluxo de instruções
Execução de um troço de código
… …
X0 0 ?
PC 0000 0014h 0204h
…
-1127
0200h
X10 0000 0100h
… …
X11 0000 0200h +3401
0104h
X12 0000 0D49h (3401)
-1127
… 0100h
… …
X31 PC sw x12,4(x11)
0014h
lw x12,4(x10)
0010h
F0
sw x12,0(x11)
F1 000Ch
Sem outras instruções o PC é incrementado de 4
após…a execução de cada instrução. Assim, as 0008h
lw x12,0(x10)
81 instruções. 0000h
ori x10,x0,100h
RISC-V Instruction Set Architecture (ISA)
Controlo do fluxo de instruções
82 82
RISC-V Instruction Set Architecture (ISA)
Controlo do fluxo de instruções
83 83
RISC-V Instruction Set Architecture (ISA)
Controlo do fluxo de instruções
84 84
Fluxo de instruções
Requer:
▪ Exemplo:
If cond then A) O teste da condição
if sequence
else
B) A execução de um
else sequence “salto” para o troço
correspondente, mudando
o fluxo (ordem) da
execução de instruções
85
Instruções de comparação e teste ARMv8
Exemplo para o ARMv8 (ISA diferente do estudado nas aulas)
Instrução RTL
Na generalidade dos
ADDS Ra,Rb,Rc Ra,Flags Rb + Rc
processadores, existem
SUBS Ra,Rb,Rc Ra,Flags Rb – Rc instruções que permitem
… alterar as flags do
processador, nomeadamente:
Z → o resultado é zero
N → o resultado é negativo
C → transporte à saída do
somador
V → Overflow
As flags são armazenadas num
registo de estado (RE)
86 86
Instruções de comparação e teste ARMv8
Exemplo para o ARMv8 (ISA diferente do estudado nas aulas)
Instrução RTL
Existem instruções de Na generalidade dos
ADDS Ra,Rb,Rc Ra,Flags Rb + Rc
controlo de fluxo de processadores, existem
SUBS Ra,Rb,Rc Ra,Flags Rb –instruções
Rc que permitem instruções que permitem
… saltar para outra zona do alterar as flags do
código, eventualmente processador, nomeadamente:
condicionadas ao estado das Z → o resultado é zero
flags
Instrução RTL N → o resultado é negativo
B IMM26 PC PC + IMM26x4 C → transporte à saída do
B.cond IMM19 If cond=true then somador
PC PC + IMM26x4
V → Overflow
Else
PC PC + 4 As flags são armazenadas num
registo de estado (RE)
87 87
RISC-V Instruction Set Architecture (ISA)
Instruções de comparação
Instrução RTL
Poderiamos pensar em mais
slt xd,xa,xb xd (xa<xb)?1:0
instruções de comparação,
slti xd,xa, imm12 xd (xa<imm12)?1:0 mas como veremos mais à
sltu xd,xa,xb xd (xa<xb)?1:0 (unsigned comparison) frente, estas são suficientes.
sltiu xd,xa, imm12 xd (xa<uimm12)?1:0 (unsigned comparison)
88
RISC-V Instruction Set Architecture (ISA)
Instruções de comparação
Instrução RTL
Poderiamos pensar em mais
slt xd,xa,xb xd (xa<xb)?1:0
instruções de comparação,
slti xd,xa, imm12 xd (xa<imm12)?1:0 mas como veremos mais à
sltu xd,xa,xb xd (xa<xb)?1:0 (unsigned comparison) frente, estas são suficientes.
sltiu xd,xa, imm12 xd (xa<uimm12)?1:0 (unsigned comparison)
Instrução RTL
As operações de
feq.s xd,fa,fb feq.d xd,fa,fb xd (fa==fb)?1:0
comparação de FP
flt.s xd,fa,fb flt.d xd,fa,fb xd (fa<fb)?1:0 escrevem num
fle.s xd,fa,fb fle.d xd,fa,fb xd (fa<=fb)?1:0 registo de inteiros!
fclass.s xd,fa fclass.d xd,fa xd class (fa)
S = Single D = Double
89 89 (C float) (C double)
RISC-V Instruction Set Architecture (ISA)
Instrução fclass
Sign Exponent Fraction
Nota: A fração não pode ser zero, caso
Signaling NaN (SP FP) S 1111 1111 1xx xxxx xxxx xxxx xxxx xxxx
contrário representa +∞/−∞
Class FP type
0 −∞
Instrução RTL 1 Negative Normal
2 Negative Subnormal
feq.s xd,fa,fb feq.d xd,fa,fb xd (fa==fb)?1:0
3 -0
flt.s xd,fa,fb flt.d xd,fa,fb xd (fa<fb)?1:0 4 +0
fle.s xd,fa,fb fle.d xd,fa,fb xd (fa<=fb)?1:0 5 Positive Subnormal
6 Positive Normal
fclass.s xd,fa fclass.d xd,fa xd class (fa)
7 +∞
8 Signaling NaN
S = Single D = Double 9 Quiet NaN
90 90 (C float) (C double)
RISC-V Instruction Set Architecture (ISA)
Controlo do fluxo de instruções
Instrução RTL
beq xa,xb,imm13 if (xa==xb) pc pc + imm13 else: pc pc + 4
bne xa,xb,imm13 if (xa!=xb) pc pc + imm13 else: pc pc + 4
blt xa,xb,imm13 if (xa<xb) pc pc + imm13 else: pc pc + 4
bge xa,xb,imm13 if (xa>=xb) pc pc + imm13 else: pc pc + 4
91
RISC-V Instruction Set Architecture (ISA)
Controlo do fluxo de instruções
Instrução RTL
beq xa,xb,imm13 if (xa==xb) pc pc + imm13 else: pc pc + 4
bne xa,xb,imm13 if (xa!=xb) pc pc + imm13 else: pc pc + 4
blt xa,xb,imm13 if (xa<xb) pc pc + imm13 else: pc pc + 4
bge xa,xb,imm13 if (xa>=xb) pc pc + imm13 else: pc pc + 4
92
RISC-V Instruction Set Architecture (ISA)
Controlo do fluxo de instruções
Instrução RTL
beq xa,xb,imm13 if (xa==xb) pc pc + imm13 else: pc pc + 4
bne xa,xb,imm13 if (xa!=xb) pc pc + imm13 else: pc pc + 4
blt xa,xb,imm13 if (xa<xb) pc pc + imm13 else: pc pc + 4
bge xa,xb,imm13 if (xa>=xb) pc pc + imm13 else: pc pc + 4
Instrução RTL
bltu xa,xb,imm13 if (xa<xb) pc pc + imm13 else: pc pc + 4 Unsigned
comparison
bgeu xa,xb,imm13 if (xa>=xb) pc pc + imm13 else: pc pc + 4
93
RISC-V Instruction Set Architecture (ISA)
Controlo do fluxo de instruções
Instrução RTL
beq xa,xb,imm13 if (xa==xb) pc pc + imm13 else: pc pc + 4
bne xa,xb,imm13 if (xa!=xb) pc pc + imm13 else: pc pc + 4
blt xa,xb,imm13 if (xa<xb) pc pc + imm13 else: pc pc + 4
bge xa,xb,imm13 if (xa>=xb) pc pc + imm13 else: pc pc + 4
Instrução RTL
bltu xa,xb,imm13 if (xa<xb) pc pc + imm13 else: pc pc + 4 Unsigned
comparison
bgeu xa,xb,imm13 if (xa>=xb) pc pc + imm13 else: pc pc + 4
Instrução RTL
jal xd,imm21 xd pc+4 and pc pc + imm21
jalr xd,xa,imm12 xd pc+4 and pc xa + imm12 Salto absoluto
94 94
RISC-V Instruction Set Architecture (ISA)
Controlo do fluxo de instruções
Instrução RTL
beq xa,xb,imm13 if (xa==xb) pc pc + imm13 else: pc pc + 4
bne xa,xb,imm13 if (xa!=xb) pc pc + imm13 else: pc pc + 4
As instruções jal/jalr são usadas nos seguintes contextos:
blt xa,xb,imm13 if (xa<xb) pc pc + imm13 else: pc pc + 4
bge
• Salto absoluto
xa,xb,imm13 if (xa>=xb) pc pc + imm13 else: pc pc + 4
• Pseudo-instrução “j imm21” ➔ “jal x0,imm21”
•
Instrução Chamadas e retorno de funções
RTL (rotinas)
bltu • (explicado mais à frente) if (xa<xb)
xa,xb,imm13 pc pc + imm13 else: pc pc + 4 Unsigned
comparison
bgeu xa,xb,imm13 if (xa>=xb) pc pc + imm13 else: pc pc + 4
Instrução RTL
jal xd,imm21 xd pc+4 and pc pc + imm21
jalr xd,xa,imm12 xd pc+4 and pc xa + imm12 Salto absoluto
95 95
RISC-V Instruction Set Architecture (ISA)
Controlo do fluxo de instruções
Do ponto de vista de
Instrução RTL
desempenho, as instruções
beq xa,xb,imm13 if (xa==xb) pc pc + imm13 else: pc pc + 4 de salto (branch) são
bne xa,xb,imm13 if (xa!=xb) pc pc + imm13 else: pc pc + 4 indesejáveis e devem ser
evitadas (quando possível).
blt xa,xb,imm13 if (xa<xb) pc pc + imm13 else: pc pc + 4
bge xa,xb,imm13 if (xa>=xb) pc pc + imm13 else: pc pc + 4
Instrução RTL
bltu xa,xb,imm13 if (xa<xb) pc pc + imm13 else: pc pc + 4 Unsigned
comparison
bgeu xa,xb,imm13 if (xa>=xb) pc pc + imm13 else: pc pc + 4
Instrução RTL
jal xd,imm21 xd pc+4 and pc pc + imm21
jalr xd,xa,imm12 xd pc+4 and pc xa + imm12 Salto absoluto
96 96
Instruction Set Architecture (ISA)
RISC-V
→ Controlo de fluxo de instruções (Exemplos práticos)
RISC-V Instruction Set Architecture (ISA)
Mapear estruturas de código C
Código C fonte:
do_pre_if; do_pre_if;
98 98
RISC-V Instruction Set Architecture (ISA)
Mapear estruturas de código C
Código C fonte:
do_pre_if; do_pre_if;
99 99
.data
a: .word 0x406ccccd # float 3.7
b: .word 0x4019999a # float 2.4
Exemplo de c: .word 0
controlo do fluxo
de instruções Memória
if (a>b) …
c=b*b; c+3
c+2
else 0
c+1
c=a/b;
X12 c=b+8
b+3
b+2
2.4
b+1
X11 b=a+8
a+3
a+2
3.7
a+1
X10 a
…
100
.data
a: .word 0x406ccccd # float 3.7
b: .word 0x4019999a # float 2.4
Exemplo de c: .word 0
105
.data
a: .word 0x406ccccd # float 3.7
b: .word 0x4019999a # float 2.4
Exemplo de c: .word 0
106
RISC-V Instruction Set Architecture (ISA)
Mapear estruturas de código C
Código C fonte:
while (cond)
{ Na prática o código diz:
1) Sai se a condição for
iterate; falsa
2) Sempre que chegamos
} ao final do loop,
devemos voltar a testar
a condição
teste:
if (!cond) branch (goto) end_while;
iterate;
branch (goto) teste;
end_while:
107 107
RISC-V Instruction Set Architecture (ISA)
Mapear estruturas de código C
Código C fonte:
while (cond)
{ Na prática o código diz:
1) Sai se a condição for
iterate; falsa Alternativa
2) Sempre que chegamos
} ao final do loop,
devemos voltar a testar
a condição
teste:
if (!cond) branch (goto) end_while;
next:
iterate;
if (cond) branch (goto) next;
end_while:
108 108
.data
v: .word 1,5,7,3,4,8,10,3,5,7 Memória
m: .word 3
Exemplo de …
controlo do fluxo m
v+36
3
7
de instruções Declaração equivalente em C: v+32 5
v+28 3
Procurar a primeira int v[]={1,5,7,3,4,8,10,3,5,7}; v+24 10
int m=3 v+20 8
ocorrência de um número
v+16 4
m numa lista v[0],v[1],…:
v+12 3
v+ 8 7
i=0; v+ 4 5
while ( v[i]!= m ) v 1
i += 1; …
109
.data
v: .word 1,5,7,3,4,8,10,3,5,7 Memória
m: .word 3
Exemplo de …
controlo do fluxo .text
m
v+36
3
7
de instruções # leitura das variáveis da memória v+32 5
la x10,v v+28 3
Procurar a primeira la x11,m v+24 10
v+20 8
ocorrência de um número lw x11,0(x11) # x11 = m v+16 4
m numa lista v[0],v[1],…:
# Inicialização do loop v+12 3
or x12,x0,x0 # i=0 (x12) v+ 8 7
i=0; v+ 4 5
while ( v[i]!= m ) v 1
i += 1; …
110
.data
v: .word 1,5,7,3,4,8,10,3,5,7 Memória
m: .word 3
Exemplo de …
controlo do fluxo .text
m
v+36
3
7
de instruções # leitura das variáveis da memória v+32 5
la x10,v v+28 3
Procurar a primeira la x11,m v+24 10
v+20 8
ocorrência de um número lw x11,0(x11) # x11 = m v+16 4
m numa lista v[0],v[1],…:
# Inicialização do loop v+12 3
or x12,x0,x0 # i=0 v+ 8 7
i=0; v+ 4 5
while ( v[i]!= m ) # Teste de condição
v 1
i += 1; lw x13,0(x10) # load v[i] …
beq x13,x11,end
Sai se Nota: para simplificar a
...
forem representação, cada
end: iguais quadrado representa 4B,
i.e., quatro posições de
memória
111
.data
v: .word 1,5,7,3,4,8,10,3,5,7
m: .word 3 Memória
Exemplo de .text
…
controlo do fluxo # leitura das variáveis da memória
m
v+36
3
7
de instruções la x10,v v+32 5
la x11,m v+28 3
Procurar a primeira v+24 10
lw x11,0(x11) # x11 = m
v+20 8
ocorrência de um número # Inicialização do loop v+16 4
m numa lista v[0],v[1],…:
or x12,x0,x0 # i=0 v+12 3
# Teste de condição v+ 8 7
i=0; C:
Linguagem v+ 4 5
whileao tipo,
Indexação ( v[i]!= m )
i.e., v+i aponta while: sll x15,x12,2 # i*4
v 1
para o elemento
i += i 1; add x15,x10,x15 # v+i*4 …
Volta
lw x13,0(x15) # load v[i] ao
Assembly:
Indexação ao byte, para obtermos o beq x13,x11,end loop Nota: para simplificar a
representação, cada
endereço (ponteiro) do elemento # Loop quadrado representa 4B,
v+i, teremos de fazer i.e., quatro posições de
addi x12,x12,1
v + i*sizeof(elemento) memória
Neste caso os elementos são de 4B j while
112 end:
.data
v: .word 1,5,7,3,4,8,10,3,5,7 Memória
m: .word 3
Exemplo de …
controlo do fluxo .text m
v+36
3
7
de instruções # leitura das variáveis da memória
v+32 5
la x10,v # tmp = v v+28 3
Procurar a primeira la x11,m v+24 10
v+20 8
ocorrência de um número lw x11,0(x11)
v+16 4
m numa lista v[0],v[1],…: # Inicialização do loop
v+12 3
or x12,x0,x0 # i=0 v+ 8 7
i=0; v+ 4 5
# Teste de condição
while (
A alternativa v[i]!=
é alterar m )
o código v 1
i += 1; while: lw x13,0(x10) # load *tmp
para: …
i=0; beq x13,x11,end
tmp = v; Volta
# Loop ao Nota: para simplificar a
while ( *tmp != m ){
addi x12,x12,1 loop representação, cada
i += 1; quadrado representa 4B,
tmp++; addi x10,x10,4 # tmp++ i.e., quatro posições de
} memória
j while
113 end:
.data
v: .word 1,5,7,3,4,8,10,3,5,7
m: .word 3 Memória
Exemplo de .text …
controlo do fluxo # leitura das variáveis da memória m
v+36
3
7
de instruções la x10,v
v+32 5
la x11,m v+28 3
Procurar a primeira lw x11,0(x11) v+24 10
v+20 8
ocorrência de um número # Inicialização do loop
v+16 4
m numa lista v[0],v[1],…: or x12,x0,x0 # i=0
v+12 3
# Teste de condição v+ 8 7
i=0; v+ 4 5
lw x13,0(x10) # load v[i]
while ( v[i]!= m ) v 1
i += 1; beq x13,x11,end
…
# Loop
while: addi x12,x12,1 Nota: para simplificar a
addi x10,x10,4 Volta representação, cada
Podemos evitar ter de realizar 2 ao quadrado representa 4B,
branches seguidos, realizando lw x13,0(x10) loop i.e., quatro posições de
uma nova comparação no final do bne x13,x11,while memória
loop.
114 end:
RISC-V Instruction Set Architecture (ISA)
Mapear estruturas de código C
Código C fonte:
for (init ; cond ; increment){ Na prática o código diz:
1) antes do ciclo while,
iterate; realiza as inicializações
2) Sai se a condição for
} falsa
3) Sempre que chegamos
ao final do loop,
devemos executar a
operação de
incremento e voltar a
testar a condição
115 115
# ler o valor de m
la x13,m
lw x13,0(x13) # m (X13)
116
# ler o valor de m
la x13,m
lw x13,0(x13) # m (X13)
117
# ler o valor de m
la x13,m
lw x13,0(x13) # m (X13)
118
# ler o valor de m
la x13,m
lw x13,0(x13) # m (X13)
119
# ler o valor de m
la x13,m
lw x13,0(x13) # m (X13)
120
# ler o valor de m
la x13,m
lw x13,0(x13) # m (X13)
121
# ler o valor de m
la x13,m
lw x13,0(x13) # m (X13)
122
Instruction Set Architecture (ISA)
Chamadas a funções & introdução à pilha
Invocação e retorno da função
res[0] = avg(v0[0],v1[0]);
res[1] = avg(v0[1],v1[1]);
res[2] = avg(v0[2],v1[2]);
}
126
Passagem de parametros
Substituir pelo código Assembly que realiza: Regra por omissão: por registo
mv (){
int main x10,”v0[0]” # por registo • Registos X10-x17 para entrada
mv x11,”v1[0]” # por registo • Registos x10-x11 para retorno
int v0[]={1,2,3};
<chamada à função>
mvint”res[0]”,x10
v1[]={4,5,6}; # por registo Nota: tipicamente é o compilador que convenciona
quais os registos que devem ser usados como
int res[3]; entrada e saída. No caso do RISC-V a especificação
do ISA convenciona diretamente a utilização de
registos indicados em cima. Diferentes arquiteturas
(ARM, Intel, …) diferentes convenções.
res[0] = avg(v0[0],v1[0]);
res[1] = avg(v0[1],v1[1]); Alternativa: pela pilha (analisado mais tarde)
• Menos eficiente
res[2] = avg(v0[2],v1[2]); • Permite a passagem de mais parametros
}
128
int avg(int a, int b){
return (a + b) / 2;
}
Suporte para
int main (){
funções int v0[]={1,2,3};
int v1[]={4,5,6};
Exemplo:
int res[3];
Código C
res[0] = avg(v0[0],v1[0]);
res[1] = avg(v0[1],v1[1]);
res[2] = avg(v0[2],v1[2]);
}
129
.data
v0: .word 1,2,3
v1: .word 4,5,6
res: .word 0,0,0 # empty vector of 3 words
132
Assumindo: .data
v0=400h
v0: .word 1,2,3
x0 0 v1: .word 4,5,6
res: .word 0,0,0
ra= x1
.text
Suporte para … …
Instrução # leitura do endereço
x5 400h executada
funções la x5,v0
x6 PC la x6,v1
la x7,res
x7
Exemplo: A pseudo-instrução la
# primeira chamada
… … traduz-se na sequencia
AUIPC+ADDI, i.e., em 2 lw x10,0(x5)
Correspondente em x10 instruções. Assim, temos lw X11,0(x6)
Assembly x11 de somar 8 ao PC jal x1,avg
… … sw X10,0(x7)
Nota: Em Assembly, # outras chamadas
geralmente usa-se a x31
…
terminologia rotina (ou # função
subrotina) em vez de
avg: add x10,x10,x11
função. PC 0000 0008h
srai X10,X10,1
jalr x0,x1,0
Após a execução da primeira instrução
133 ra = return address
Assumindo: .data
v0=400h
v0: .word 1,2,3
x0 0 v1: .word 4,5,6
res: .word 0,0,0
ra= x1
.text
Suporte para … …
# leitura do endereço
x5 400h
funções Instrução
executada
la
la
x5,v0
x6,v1
x6 40Ch
x7 PC la x7,res
Exemplo: # primeira chamada
… … A pseudo-instrução la
traduz-se na sequencia lw x10,0(x5)
Correspondente em x10 AUIPC+ADDI, i.e., em 2 lw X11,0(x6)
Assembly x11 instruções. Assim, temos jal x1,avg
de somar 8 ao PC sw X10,0(x7)
… …
Nota: Em Assembly, # outras chamadas
geralmente usa-se a x31
…
terminologia rotina (ou # função
subrotina) em vez de
avg: add x10,x10,x11
função. PC 0000 0010h
srai X10,X10,1
jalr x0,x1,0
Após a execução da segunda instrução
134 ra = return address
Assumindo: .data
v0=400h
v0: .word 1,2,3
x0 0 v1: .word 4,5,6
res: .word 0,0,0
ra= x1
.text
Suporte para … …
# leitura do endereço
x5 400h
funções Instrução
la
la
x5,v0
x6,v1
x6 40Ch
executada la x7,res
x7 418h
Exemplo: # primeira chamada
… …
PC lw x10,0(x5)
Correspondente em x10 lw X11,0(x6)
Assembly x11 A pseudo-instrução la jal x1,avg
traduz-se na sequencia sw X10,0(x7)
… … AUIPC+ADDI, i.e., em 2
Nota: Em Assembly, # outras chamadas
x31 instruções. Assim, temos
geralmente usa-se a de somar 8 ao PC …
terminologia rotina (ou # função
subrotina) em vez de
avg: add x10,x10,x11
função. PC 0000 0018h
srai X10,X10,1
jalr x0,x1,0
Após a execução da terceira instrução
135 ra = return address
Assumindo: .data
v0=400h
v0: .word 1,2,3
x0 0 v1: .word 4,5,6
res: .word 0,0,0
ra= x1
.text
Suporte para … …
# leitura do endereço
x5 400h
funções la
la
x5,v0
x6,v1
x6 40Ch
la x7,res
x7 418h
Exemplo: # primeira chamada
Instrução
… …
executada lw x10,0(x5)
Correspondente em x10 1 PC lw X11,0(x6)
Assembly x11 jal x1,avg
… … sw X10,0(x7)
Nota: Em Assembly, # outras chamadas
geralmente usa-se a x31
…
terminologia rotina (ou # função
subrotina) em vez de
avg: add x10,x10,x11
função. PC 0000 001Ch
srai X10,X10,1
jalr x0,x1,0
▪ Para realizar a chamada a uma função não é preciso conhecer os detalhes da função,
basta saber a convenção e o cabeçalho da função:
142
Passagem de parametros
Passagem por registo (método por omissão)
▪ Para realizar a chamada a uma função não é preciso conhecer os detalhes da função,
basta saber a convenção e o cabeçalho da função:
143
Considere a existência de uma função
res = my_fun ( x , y , k )
Com
f1 = 3.5, f2=37.21, k=2
144
Considere a existência de uma função
res = my_fun ( x , y , k )
Com
f1 = 3.5, f2=37.21, k=2
145
.data
x: .word 0x40600000 # 3.5 em floating point (float)
y: .word 0x4214d70a # 37.21 em floating point (float)
Passagem de K: .word 2
registo .text
la x10,x
res = my_fun ( x , y, k ) flw f10,0(x10) # inicialização do 1º argumento
la x10,y
x = 3.5, y=37.21, k=2
flw f11,0(x10) # inicialização do 2º argumento
la x10,K
lw x10,0(x10) # inicialização do 3º argumento
la x10,res
fsw f10,0(x10)
146
Impacto da invocação de uma função
▪ Para realizar a chamada a uma função não é preciso conhecer os detalhes da função,
basta saber a convenção e o cabeçalho da função:
147
Impacto da invocação de uma função
Convenção do compilador
149
Pilha
▪ PILHA (stack):
▫ Espaço reservado na memória para guardar dados temporários;
▫ O acesso a este espeço de memória é feito segundo uma política do
tipo “Last-in-first-out (LIFO)”, i.e., o último elemento a entrar é o
primeiro a sair.
150
Pilha
151
Pilha
152
Pilha
Memória
FFFF FFFFh
Program
153 0000 0000h
Pilha no RISC-V
Operação de PUSH
PUSH
Implementado como:
addi x2,x2,-4
sw xn,0(x2)
… …
0000 0000 0000 0000h 0000 0000 0000 0000h
154
Pilha no RISC-V
Operação de PUSH
Implementado como:
addi x2,x2,-12
sw xa,8(x2)
sw xb,4(x2)
sw xc,0(x2)
… …
0000 0000 0000 0000h 0000 0000 0000 0000h
155
Pilha no RISC-V
Operação de POP
Implementado como:
lw xd,0(x2)
addi x2,x2,4
… …
0000 0000 0000 0000h 0000 0000 0000 0000h
156
Pilha no RISC-V
Operação de POP
Implementado como:
lw xe,0(x2)
lw xf,4(x2)
addi x2,x2,8
… …
0000 0000 0000 0000h 0000 0000 0000 0000h
157
Informação
Operações sobre a pilha
158
Passagem de parametros
Passagem por registo (método por omissão)
▪ Para realizar a chamada a uma função não é preciso conhecer os detalhes da função,
basta saber a convenção e o cabeçalho da função:
Nota: em linguagem C uma lista de valores é sempre passada por referencia (i.e., por ponteiro),
159 mas há linguagens que suportam a passagem por valor
Passagem de parametros
Passagem por registo (método por omissão)
▪ Para realizar a chamada a uma função não é preciso conhecer os detalhes da função,
basta saber a convenção e o cabeçalho da função:
▪ Para realizar a chamada a uma função não é preciso conhecer os detalhes da função,
basta saber a convenção e o cabeçalho da função:
2. Remover a
alocação de
espaço na pilha
161
Considere a existência de uma função
Passagem de struct time timediff (struct time t1, struct time t2, int mode);
registo
struct time {
int hour;
int minute;
int sec;
int milisecond;
}
Realize o código que determina:
res = my_fun ( t1 , t2 , 0 )
Com
t1 = {23,4,25,125} , t2 = {12,5,14,671}
162
Considere a existência de uma função
Passagem de struct time timediff (struct time t1, struct time t2, int mode);
registo
struct time {
int hour;
int minute;
int sec;
res = my_fun ( t1 , t2 , 0 ) int milisecond;
}
Realize o código que determina:
res = my_fun ( t1 , t2 , 0 )
Com
pilha pilha pilha x10
t1 = {23,4,25,125} , t2 = {12,5,14,671}
163
.data
t1: .word 23,4,25,125 # struct t1
t2: .word 12,5,14,671 # struct t2
Passagem de res: .zero 16 # output
res = my_fun ( t1 , t2 , 0 )
t1
(16B)
t2
(16B)
Reserva de espaço na pilha de acordo com os requisitos…
SP →
As duas estruturas (t1 e t2) são passadas pela pilha!
164
.data
t1: .word 23,4,25,125 # struct t1
t2: .word 12,5,14,671 # struct t2
Passagem de res: .zero 16 # output
res = my_fun ( t1 , t2 , 0 )
struct time {
hour int hour;
t1 minute int minute;
(16B) second int sec;
milisecond int milisecond;
}
Mantemos a ordem da declaração!
t2
(16B)
SP →
165
.data
t1: .word 23,4,25,125 # struct t1
t2: .word 12,5,14,671 # struct t2
Passagem de res: .zero 16 # output
166
.data
t1: .word 23,4,25,125 # struct t1
t2: .word 12,5,14,671 # struct t2
Passagem de res: .zero 16 # output
(copy t1 to stack)
parametros por .text
la x10,t1
lw x11,0(x10)
registo (…)
sw x11,28(sp)
add sp,sp,-32 # 2(structs)*4(ints)*4(B/int)
lw x11,4(x10)
res = my_fun ( t1 , t2 , 0 )
(copy t1 to stack)
sw x11,24(sp)
la x10,t2
lw x11,8(x10)
lw x11,0(x10)
sw x11,20(sp)
sw x11,12(sp) # hour
lw x11,4(x10)
lw x11,12(x10)
t1 sw x11,8(sp) # minute sw x11,16(sp)
(16B)
lw x11,8(x10)
sw x11,4(sp) # second
hour lw x11,12(x10)
t2 minute sw x11,0(sp) # milisecond
(16B) second (…)
SP → milisecond
167
.data
t1: .word 23,4,25,125 # struct t1
t2: .word 12,5,14,671 # struct t2
Passagem de res: .zero 16 # output
(copy t1 to stack)
parametros
(copy t2por
to stack)
.text
la x10,t1
lw x11,0(x10)
registo lw x11,0(x10)
la x10,t2
(…)
sw x11,28(sp)
add sp,sp,-32 # 2(structs)*4(ints)*4(B/int)
sw x11,12(sp) lw x11,4(x10)
res = my_fun ( t1lw, t2 , 0x11,4(x10)
)
(copy t1 to stack)
sw x11,24(sp)
(copy t2 to stack)
sw x11,8(sp) lw x11,8(x10)
mv x10,x0
lw x11,8(x10) sw x11,20(sp)
jal my_fun lw x11,12(x10)
sw x11,4(sp)
(…)
lw x11,12(x10) sw x11,16(sp)
sw x11,0(sp)
Estado da stack após
a chamada à função
hour
res minute
(16B) second
SP → milisecond
168
.data
t1: .word 23,4,25,125 # struct t1
t2: .word 12,5,14,671 # struct t2
Passagem de res: .zero 16 # output
(copy t1 to stack)
parametros
(copy t2por
to stack)
.text
la x10,t1
lw x11,0(x10)
registo lw x11,0(x10)
la x10,t2
(…)
sw x11,28(sp)
add sp,sp,-32 # 2(structs)*4(ints)*4(B/int)
sw x11,12(sp) lw x11,4(x10)
res = my_fun ( t1lw, t2 , 0x11,4(x10)
)
(copy t1 to stack)
sw x11,24(sp)
(copy t2 to stack)
sw x11,8(sp) lw x11,8(x10)
mv x10,x0
lw x11,8(x10) sw x11,20(sp)
jal my_fun lw x11,12(x10)
sw x11,4(sp)
lw x11,12(x10) la x10,res sw x11,16(sp)
sw x11,0(sp) lw x11,12(sp)
sw x11,0(x10) Estado da stack após
lw x11,8(sp) a chamada à função
sw x11,4(x10)
lw x11,4(sp) hour
sw x11,8(x10) res minute
lw x11,0(sp) (16B) second
sw x11,12(x10) SP → milisecond
addi sp,sp,16
169 (…)
Passagem de parametros pela pilha
170
Impacto da invocação de uma função
Convenção do compilador (revisão)!
(…)
#chamada a uma função
li x10,3
li x11,5
jal ra, max # os valores guardados em todos os registos
# temporários assumem-se perdidos! Não há garantia que os
# os valores ainda estejam nos registos
172
Salvaguarda de registos
173
Salvaguarda de registos
(…)
#salvaguarda de contexto
addi sp,sp,-8 # assumindo RV64 – registos de 64 bits
sd x28,0(sp)
#chamada à função
li x10,3
li x11,5
jal ra, max
#reposição de contexto
ld x28,0(sp)
addi sp,sp,8 # assumindo RV64 – registos de 64 bits
174
Instruction Set Architecture (ISA)
Escrita do código de uma função
Estrutura de uma função em Assembly
Corpo da função
return x
}
176
Estrutura de uma função em Assembly
177
Estrutura de uma função em Assembly
1. Salvaguarda de contexto
2. Leitura dos operandos (argumentos) da pilha Retirar da pilha os argumentos da função
3. Declaração de variáveis na pilha (variáveis locais),Ex:
se necessário
colocar X e Y em registos
4. Corpo da função fld f0,24(sp) ; Y
6. Reposição de contexto …
Obs: Assumindo que X é do tipo int X 4B
7. Retorno da função Y 8B
e que Y é do tipo double, e que {X,Y}
X20 8B
fazem parte de uma estrutura, e portanto X21 8B
foram passados pela pilha SP→ X22 8B
…
179
Estrutura de uma função em Assembly
Corpo da função
return x
}
180
Estrutura de uma função em Assembly
…
X 4B
Estrutura do código da função: Y 8B
X20 8B
X21 8B
1. Salvaguarda de contexto SP (before)→ X22 8B
int
2. Leitura dos operandos (argumentos) da pilha int
3. Declaração de variáveis na pilha (variáveis locais), se necessário SP (after)→ double
4. Corpo da função
5. Escrita do resultado na pilha
fun(…){ Reserva de espaço na pilha para as variáveis locais à
6. Reposição de contexto função (ex: 2 x int, 1x double):
int a,b;
7. Retorno da função addi sp,sp,-16 ; 2x4B + 1x8B
float f;
(…)
}
181 Observação: o compilador só declara as variáveis na pilha, se não existirem registos suficientes para armazenar estas mesmas variáveis.
Estrutura de uma função em Assembly
…
X 4B
Estrutura do código da função: Y 8B
X20 8B
Até ao topo são 52B X21 8B
1. Salvaguarda de contexto X22 8B
int
2. Leitura dos operandos (argumentos) da pilha int
3. Declaração de variáveis na pilha (variáveis locais), se necessário SP→ double
4. Corpo da função
5. Escrita do resultado na pilha A escrita do resultado na pilha (quando necessário)
ocupa o espaço dos argumentos de entrada...
6. Reposição de contexto Relembra-se que após a chamada à função, na pilha fica apenas o resultado.
7. Retorno da função Exemplo, retornar a estrutura {long long,double} no
topo da pilha:
sw x22,44(sp) # 52B (até ao topo)-8B = 44B
sw f12,36(sp) # 44B (até à anterior)-8B = 36B
182
Estrutura de uma função em Assembly
…
SP (after)→ X 4B
Estrutura do código da função: Y 8B
X20 8B
X21 8B
1. Salvaguarda de contexto X22 8B
int
2. Leitura dos operandos (argumentos) da pilha int
3. Declaração de variáveis na pilha (variáveis locais), se necessário SP (before)→ double
4. Corpo da função
5. Escrita do resultado na pilha Ajustar ainda o valor
return_type final da pilha, após a reposição de contexto
function_name(argumentos){
6. Reposição de contexto lw declaração de variáveis locais
x22,16(sp)
7. Retorno da função lw x21,20(sp)
Corpo da função
lw x20,24(sp)
addi return x # 16B (vars. temp.) + 24B (regs. salvaguardados)
sp,sp,36
} # + 12B relativos aos argumentos de entrada
# - 16B relativos aos argumentos de saida
183
Código de uma
função
Realize o código da função
184
maxvalue:
185
maxvalue:
função maxvalue_next:
addi x11,x11,8
Realize o código da função addi x10,x10,-1
beq x10,x0,maxvalue_end # exit if no more elements
186
Terminar
maxvalue:
ble x10,x0,maxvalue_end # exit is N<=0
fld f10,0(x11) # f10 <– current max
função
addi x11,x11,8
addi x10,x10,-1
beq x10,x0,maxvalue_end # exit if no more elements
Realize o código da função
fld f11,8(x11)
187
Código de uma
função
Realize o código da função
struct vector_stats{
float min;
float avg;
float max
}
188
Passo 1: Código da função
maxvalue:
li x12,0x7f800000 # +inf in SP FP
fmv.s.w f10,x12 # f10 (min) = +inf
fsgnjn.s f11,f10,f10 # f11 (max) = -f10 = -inf
189
maxvalue:
li x12,0x7f800000 # -inf in SP FP
fmv.s.w f10,x12 # f10 (min) = +inf
fsgnjn.s f11,f10,f10 # f11 (max) = -f10 = -inf
190
Passo 3: Colocar o resultado na pilha
maxvalue:
li x12,0x7f800000 # -inf in SP FP
fmv.s.w f10,x12 # f10 (min) = +inf
fsgnjn.s f11,f10,f10 # f11 (max) = -f10 = -inf
191
Passo 4: retornar da função
maxvalue:
li x12,0x7f800000 # -inf in SP FP
fmv.s.w f10,x12 # f10 (min) = +inf
fsgnjn.s f11,f10,f10 # f11 (max) = -f10 = -inf
fmv.s.w f12,x0 # f12 (sum) = 0
192
Código de uma
função
Realize o código da função
193
maxvalue:
Passo 1: recuperar o passo 1 para o caso em que o vetor
é passado
li por registo # +inf in SP FP
x12,0x7f800000
fmv.s.w f10,x12 # f10 (min) = +inf
fsgnjn.s f11,f10,f10 # f11 (max) = -f10 = -inf
194
PILHA À ENTRADA DA FUNÇÃO
maxvalue:
Value N
li x12,0x7f800000 # +inf in SP FP …
fmv.s.w f10,x12 # f10 (min) = +inf Value 3
fsgnjn.s f11,f10,f10 # f11 (max) = -f10 = -inf Value 2
Código de uma fmv.s.w f12,x0
fcvt.s.w f14,x10
# f12 (sum) = 0
# f14 (N)
SP → Value 1
função
ble x10,x0,maxvalue_end # exit is N<=0
maxvalue_next:
Realize o código da função fld f13,0(x11)
fmin.s f10,f10,f13
pilha x10 pilha fmax.s f11,f11,f13 X11 nunca foi definido!!!!
mystruct stats(int N, list of floats);
fadd.s f12,f12,f13
addi x11,x11,4 1. Começamos por escrever o
Que determina o minimo, máximo e addi x10,x10,-1 Código admitindo que foi
média do vetor v com dimensão N. bne x10,0,maxvalue_next # loop if there are more elements
Devolve uma estrutura: fdiv.d f12,f12,f14 # compute average
maxvalue_end:
struct vector_stats{
float min;
float avg;
float max
}
Passo 2: inicializar os registos cujo valor está na pilha
Neste caso, o endereço do inicio do vetor é a primeira
posição do vetor na pilha
195
Completo
maxvalue_end:
mv x11,sp
li x12,0x7f800000 # +inf in SP FP
fmv.s.w f10,x12 # f10 (min) = +inf
fsgnjn.s f11,f10,f10 # f11 (max) = -f10 = -inf
197
# int power(int x, int pow){
# if (pow==0) return 1;
# else return power(x,pow-1)*x;
# }
Código de uma power:
198
Passo 2: Verificar registos perdidos
# int power(int x, int pow){ (temporários) em chamadas a funções
# if (pow==0) return 1;
# É
else return power(x,pow-1)*x; preciso salvaguardar na pilha x10 e x1
# }
Código de uma power:
199
Salvaguarda dos registos
# int power(int x, int pow){
# if (pow==0) return 1;
# else return power(x,pow-1)*x;
# }
Código de uma power:
IGNORE AS CONVENÇÕES DE
UTILIZAÇÃO DE REGISTOS E FAÇA
TODA A PASSAGEM DE
PARAMETROS PELA PILHA!
202
Passo 1: tradução direta do Código,
# int power(int x, int pow){ admitindo que os parametros são
# if (pow==0) return 1; passados por registo
# else return power(x,pow-1)*x;
# }
Código de uma
função
power:
bne x11,x0,power_else
Realize o código da função
addi x10,x0,1
jalr x0,ra,0
int power(int x, int pow);
power_else:
Que determina de forma recursiva
addi x11,x11,-1
y=x^pow
jal power Alterar passagem de parametros que
mul x10,x10,x11 agora é feita pela pilha
IGNORE AS CONVENÇÕES DE
UTILIZAÇÃO DE REGISTOS E jalr x0,ra,0
FAÇA TODA A PASSAGEM DE
PARAMETROS PELA PILHA!
203
Passo 2: passagem de parametros
# int power(int x, int pow){ pela pilha
# if (pow==0) return 1;
# else return power(x,pow-1)*x;
# }
Código de uma power:
PILHA À ENTRADA DA PRÓXIMA
função bne x11,x0,power_else INVOCAÇÃO DA FUNÇÃO
addi x10,x0,1
jalr x0,ra,0 x 4B = int
Realize o código da função
SP → pow-1 4B = int
power_else:
int power(int x, int pow);
addi x11,x11,-1
addi sp,sp,-8
Que determina de forma recursiva
sw x10,4(sp)
y=x^pow
sw x11,0(sp) PILHA À SAÍDA DA PRÓXIMA
INVOCAÇÃO DA FUNÇÃO
jal power
IGNORE AS CONVENÇÕES DE
UTILIZAÇÃO DE REGISTOS E lw x11,0(sp)
SP → power(x,pow-1) 4B = int
FAÇA TODA A PASSAGEM DE addi sp,sp,4
PARAMETROS PELA PILHA!
mul x10,x10,x11
jalr x0,ra,0
204
Passo 2b: esquecemo-nos de
# int power(int x, int pow){ salvaguardar o registo ra
# if (pow==0) return 1;
Nota: o ra poderia ser salvaguardado logo no inicio da rotina.
# else return power(x,pow-1)*x; Em rotinas que têm várias chamadas a funções é preferível.
# } Neste exemplo, como só há uma chamada, esta solução evita
a salvaguarda no caso em que pow=0.
power:
Código de uma bne x11,x0,power_else
PILHA À ENTRADA DA PRÓXIMA
função addi
jalr
x10,x0,1
x0,ra,0
INVOCAÇÃO DA FUNÇÃO
ra 8B = registo RV64
Realize o código da função power_else:
addi x11,x11,-1 x 4B = int
205
Passo 3:
# int power(int x, int pow){ a) ler os argumentos de entrada da
# if (pow==0) return 1;
pilha e colocar em (x10,x11);
# else return power(x,pow-1)*x;
# } b) colocar o resultado (x10) na pilha
power:
Código de uma lw
lw
x10,4(sp)
x11,0(sp)
PILHA À ENTRADA DA FUNÇÃO
Código de uma sd
sd
x11,8(sp)
x12,0(sp)
função lw
lw
x10,28(sp)
x11,24(sp)
# leitura dos argumentos de entrada da pilha
209
Frame pointer
210
Frame pointer
SP salvaguardar
salvaguardados salvaguardados salvaguardados
211
Frame pointer
▪ O FP (Frame Pointer) fornece uma base estável para cada variável O FP voltou à posição
➢ Aponta para a primeira word da stack relativa à função. correspondente à
função mãe
▪ Não esquecer: Após o JAL e Antes de sair da
➢ À saída da função, o SP deve apontar para
o ultimo byte de retorno da função salvaguarda de FP função
contexto
? ?
FP Retorno
Argumentos da
função SP
Registos
salvaguardados
O SP
SP aponta para
o resultado
da função
212
Código usando o frame pointer (opcional!!!)
power:
addi sp,sp,-32 # salvaguarda de contexto (x10,x11,x12,fp)
sd fp,24(sp) ESTADO DA PILHA
sd x10,16(sp)
sd x11,8(sp)
sd x12,0(sp) FP → x
Código de uma
addi fp,sp,36
pow
lw x10,0(fp) # leitura dos argumentos de entrada da pilha
lw x11,-4(fp) fp
função bne
addi
x11,x0,power_else # verifica se pow==0
x10,x0,1 # return 1 se pow==0
x10
j power_return x11
SP → x12
Realize o código da função power_else:
addi x11,x11,-1 # else: coloca os parametros de entrada na pilha (e ra)
addi sp,sp,-16
int power(int x, int pow); sd ra,8(sp)
sw x10,4(sp)
sw x11,0(sp)
jal power # call: power(x,pow-1)
Que determina de forma recursiva lw x11,0(sp)
y=x^pow ld ra,4(sp) # retira o resultado da pilha
addi sp,sp,12
mul x10,x10,x11 # calcula power(x,pow-1) * x
Código de uma }
IGNORE AS CONVENÇÕES DE
UTILIZAÇÃO DE REGISTOS E int main (){
FAÇA TODA A PASSAGEM DE
PARAMETROS PELA PILHA! int vector[]={2,10,-27,4,13,-7};
int maximum;
Código de uma }
IGNORE AS CONVENÇÕES DE
UTILIZAÇÃO DE REGISTOS E int main (){
FAÇA TODA A PASSAGEM DE
PARAMETROS PELA PILHA! int vector[]={2,10,-27,4,13,-7};
int maximum;
216
2. Escrever o código da salvaguarda de contexto e reposição de contexto
(todos os registos alterados pela função)
função sw x12,0(sp)
Código de uma }
IGNORE AS CONVENÇÕES DE
UTILIZAÇÃO DE REGISTOS E int main (){
FAÇA TODA A PASSAGEM DE
PARAMETROS PELA PILHA! int vector[]={2,10,-27,4,13,-7};
int maximum;
IGNORE AS CONVENÇÕES DE
UTILIZAÇÃO DE REGISTOS E FAÇA
TODA A PASSAGEM DE
PARAMETROS PELA PILHA!
221
1. Fazer o corpo da função, assumindo a entrada e saída por registo, p. ex.,
X10 e X11 para entrada de v e N, X12 para a variável i e X13 para max (saída)
maxN: (salvaguarda de contexto)
(leitura dos argumentos da pilha)
Código de uma
sw x11,12(sp)
sw x12,8(sp) …
função sw x13,4(sp) V 4B
sw x14,0(sp) Estado da pilha N 4B
int maxN(int v[], int N){ rax1 4B
(leitura dos argumentos da pilha)
(corpo da função – ver slide anterior)
x10 4B
int i, max=v[0]; x11 4B
(escrita do resultado na pilha)
for (i=1; i<N; i++)
x12 4B
max=max2(max,v[i]); x13 4B
lw x14,0(sp)
SP → x14 4B
lw x13,4(sp)
return max; …
lw x12,8(sp)
} lw x11,12(sp)
lw x10,16(sp)
IGNORE AS CONVENÇÕES DE lw x1,20(sp) # salvaguarda de X0-X4 + LR
UTILIZAÇÃO DE REGISTOS E FAÇA
addi sp,sp,28 # 6 registos de 4B + 4B (argumento N)
TODA A PASSAGEM DE
PARAMETROS PELA PILHA!
ret
224 NESTE EXEMPLO ESTAMOS A USAR RV32, i.e., REGISTOS DE 4B
3. Leitura dos argumentos e escrita do resultado
X10 e X11 para entrada de v e N, X12 para a variável i e X13 para max (saída)
IGNORE AS CONVENÇÕES DE
UTILIZAÇÃO DE REGISTOS E FAÇA
TODA A PASSAGEM DE
PARAMETROS PELA PILHA!
Código de uma }
IGNORE AS CONVENÇÕES DE
UTILIZAÇÃO DE REGISTOS E int main (){
FAÇA TODA A PASSAGEM DE
PARAMETROS PELA PILHA! int vector[]={2,10,-27,4,13,-7};
int maximum;
227
.data
N: .word 6
vector: .word 2,10,-27,4,13,-7
Maximum: .word 0
Código de uma
função .text
la X10,vector # inicialização das variáveis
la x11,N
Exemplo: lw x11,0(x11)
E onde está a inicialização do SP?
int main(…)
Geralmente faz parte da competência do addi sp,sp,-12 # chamada a maxN
Sistema Operativo (SO) inicializar o SP sw x10,4(sp)
(mais detalhe nas próximas aulas). sw X11,0(sp)
jal x1,maxN
Contudo, se não existir SO (ex: no caso de
um microcontrolador), então deve-se lw x11,0(sp) # retirar o resultado da pilha
começar o programa com a inicialização do addi sp,sp,4
SP, ex:
lw x10,Maximum # Escrever o res. na mem
li SP,0x8000 sw x11,0(x11)
228
;===================================================== ;==========================================================
.data
N: .word 6 maxN: addi sp,sp,-24 # espaço para 6 pal. de 4B
vector: .word 2,10,-27,4,13,-7 sw x1,20(sp) # salvaguarda de X0-X4 + LR
Maximum: .word 0 sw x10,16(sp)
sw x11,12(sp)
.text sw x12,8(sp)
la X10,vector # inic. das variáveis sw x13,4(sp)
la x11,N sw x14,0(sp)
Código de uma lw
addi
sw
x11,0(x11)
sp,sp,-8
x10,4(sp)
# chamada a maxN
lw
lw
X10,28(sp)
X11,24(sp)
função
lw x13,0(x10) # X13 (max) = v[0]
sw X11,0(sp)
jal x1,maxN ori x12,x0,1 # X12 (i) = 1
lw x11,0(sp) # retirar o res. Da pilha
addi sp,sp,4 maxN_loop: bge x12,x11, maxN_sai # if i>=N, sai do for
lw x10,Maximum # Escrever o res. na mem addi x10,x10,4 # X10 aponta para v[i]
sw x11,0(x11) lw x14,0(x10) # X14 = v[i]
end: b end
; chamada a max2
;===================================================== addi sp,sp,-8 # reserva 2 x 4B (int)
max2: addi sp,sp,-12 # salvaguarda de X10-X12 sw x13,4(sp) # coloca max na pilha
sw x10,8(sp) sw x14,0(sp) # coloca v[i] na pilha
sw x11,4(sp) jal x1,max2
sw x12,0(sp) lw x13,0(sp) # retira o res. da pilha
addi sp,sp,4 # ajusta a pilha
lw x10,16(sp) # leitura dos operandos
lw x11,12(sp) # X10=a e X11=b
; iterador do ciclo (i++)
bge x11,x10,max_else # (b>=a)?else:if addi x12,x12,#1
mv x12,x10 # resultado if j maxN_loop
jal x0,max_fim maxN_sai: sw x13,28(sp)
max_else: mv X12,X11 # resultado else lw x14,0(sp)
lw x13,4(sp)
max_fim: sw X12,16(sp) # Escrita do resultado(X12) lw x12,8(sp)
lw x11,12(sp)
lw x12,0(sp) # Reposição de X10,X11,X12 lw x10,16(sp)
lw x11,4(sp) lw x1,20(sp) # salvaguarda de X0-X4 + LR
lw x10,8(sp) addi sp,sp,28 # 6 registos de 4B + 4B
addi sp,sp, 16 # mantem na pilha apenas o ret
ret # resultado
;=====================================================
229 ;======================================================
▪ Considere a implementação da função fatorial de forma
recursiva
230
▪ Considere a implementação da função fatorial de forma
recursiva
231
▪ Considere a implementação da função fatorial de forma
recursiva
232
▪ Considere a implementação da função fatorial de forma
recursiva
233
▪ Considere a implementação da função fatorial de forma
recursiva
5
x18
x19
ra
▪ Considere que a passagem de parâmetros é sempre realizada
4
Exercicio pela pilha e que a implementação da função requer a
X18
x19
salvaguarda de 2 registos de uso geral (x18 e x19) em cada
ra
int factorial(int n){ 3
if (n==0)
chamada.
x18
x19
return 1; ra
else
return fatorial(n-1)*n;
➢ Considerando a invocação factorial(5), determine o
2
x18
} estado da pilha quando esta atinge o valor máximo.
x19
ra
1
x18
x19
ra • A função fatorial guarda x18 e x19.
0
X18
• Guarda ainda o ra!
X19 • Chama factorial(2)…(1)…(0)
SP ra • Admitindo que x18, x19 e ra são sempre
preservados, independentemente do caminho
234
seguido no if.
▪ Considere a implementação da função fatorial de forma
recursiva
5
x18
x19
ra
▪ Considere que a passagem de parâmetros é sempre realizada
4
Exercicio pela pilha e que a implementação da função requer a
x18
x19
salvaguarda de 2 registos de uso geral (x18 e x19) em cada
ra
int factorial(int n){ 3
if (n==0)
chamada.
x18
x19
return 1; ra
else
return fatorial(n-1)*n;
➢ Considerando a invocação factorial(5), determine o
2
x18
} estado da pilha quando esta atinge o valor máximo.
x19
ra
1
x18
x19
ra Para um dado n, serão ocupados:
0
x18
• n x 4(palavras)x4B + 4x4B = 16 (n+1) B
x19
SP ra
235
▪ Considere a implementação da função fatorial de forma
recursiva
1024
Para um dado n, 16 𝑛 + 1 = 1024 ⇒ 𝑛 + 1 = = 64
serão ocupados: 16
⇒ 𝑛𝑀𝐴𝑋 = 64 − 1 = 63
• 16 (n+1)
236
Reserva de espaço na stack
▪ Para simplificar, a especificação do RISC-V admite que o SP tem de estar sempre alinhado a 5
x18
uma palavra de 16B
▫ Se precisarmos de alocar xB na pilha (para passagem de parâmetros, salvaguarda de
𝑥
x19
ra
contexto, ou para variáveis temporárias), alocamos y blocos de 16B, tal que 𝑦 = 16 . 4
x18
x19
▪ No caso da função fatorial:
ra
3
▫
x19
Para salvaguarda de registos (3) alocamos mais 16B. Como em RV32 os registos são ra
1
de 4B, precisamos de 12B. Alocamos portanto mais um bloco, desperdiçando 4B
x18
▫ No total, vamos precisar de alocar 2 blocos por cada chamada a fatorial (um para
x19
ra
argumentos, outro para salvaguarda de contexto). 0
x18
▫ Para factorial(n), são realizadas n chamadas ➔ alocação de 𝑛 + 1 × 2 × 16B x19
ra
237
Registos
Convenção do compilador
238 238
Registos
Convenção do compilador
Sempre zero
239 239
Registos
Convenção do compilador
240 240
Registos
Convenção do compilador
241 241
Registos
Convenção do compilador
244 244
Registos int M(…){
(…)
y=f(xpto);
Convenção do compilador (…)
return;
245 245
Registos int M(…){
(…)
y=f(xpto);
Convenção do compilador (…)
return;
➢ Exceptuam-se os registos
-x0 (o valor é sempre 0)
-x2 (Stack Pointer)
247
int M(…){
Salvaguarda de registos (…)
A Passagem de parametros para a A passagem de parametros para a função M é realizada por registo
função M é realizada pela pilha (x10-x17 para entrada, x10-x11 para saída).
(Usa-se a pilha apenas se o número de parametros entrada for maior que 8 e de saída maior que 2.)
248
int M(…){
Salvaguarda de registos (…)
249
int M(…){
Chamada a uma função K(…)
Na chamada a uma função K(…) Na chamada a uma função K(…) que segue a convenção do
que NÃO segue a convenção do compilador…
compilador…
Não é preciso cuidados extra. Se a função M (caller) necessita de um valor que se encontra num
registo temporário ou de argumento E/S, para garantir que este se
mantem inalterado, M deve salvaguardar esse valor antes de chamar
K (callee).
250
Instruction Set Architecture (ISA)
Codificação das instruções
Codificação das instruções
32 bits (4B)
252
Codificação das instruções
Formato das instruções
253
Codificação das instruções
Formato das instruções
254
Codificação das instruções
Formato das instruções
add
sub
funct3? funct7? …
lb
opcode
?
lh
funct3? lw
…
lui
255 …
Quick Reference
Guide
Disponível na página da UC!!!
256
Exemplo 1
Codificação da instrução:
addi x1,x1,1
(increment)
257
Resposta: imm | ra | funct3 | rd | opcode
Exemplo 1
Codificação da instrução:
addi x1,x1,1
(increment)
258
Resposta: imm | ra | 000 | rd | 0010011
Exemplo 1
Codificação da instrução:
addi x1,x1,1
(increment)
259
Resposta: 0000 0000 0001 0000 1000 0000 1001 0011 = 00108093h
Exemplo 1
Codificação da instrução:
addi x1,x1,1
(increment)
260
Exemplo 2
Codificação da instrução:
ret
(return from subrotine)
261
Exemplo 2
Codificação da instrução:
ret
(return from subrotine)
262
Exemplo 2
Codificação da instrução:
ret
(return from subrotine)
263
Exemplo 3
Codificação da instrução:
call my_function
264
Exemplo 3
Codificação da instrução:
call my_function
(return from subrotine)
265
Exemplo 3
Codificação da instrução:
call my_function
(return from subrotine)
266
Exemplo 3
Codificação da instrução:
call my_function
(return from subrotine)
auipc + jalr
1) auipc ra,imm31:12
2) jalr ra,ra,imm11:0
267
Exemplo 3
Codificação da instrução:
call my_function
(return from subrotine)
auipc + jalr
1) auipc ra,imm31:12
2) jalr ra,ra,imm11:0
call my_function
(return from subrotine)
auipc + jalr
1) auipc ra,imm31:12
2) jalr ra,ra,imm11:0
Parte alta: 4h+1h=5h auipc ra,5: 0000 0000 0000 0000 0101 00001 0010111
Parte baixa: A28h-1000h=A28h
call my_function
(return from subrotine)
auipc + jalr
1) auipc ra,imm31:12
2) jalr ra,ra,imm11:0
Parte alta: 4h+1h=5h auipc ra,5: 0000 0000 0000 0000 0101 00001 0010111
Parte baixa: A28h-1000h=A28h jalr ra,ra,0xa28: 1010 0010 1000 00001 000 00001 1100111
270
Exemplo 4
Codificação da instrução:
jal x1,0xa740
271
Exemplo 4
Codificação da instrução:
jal x1,0xa740
272
Exemplo 4
Codificação da instrução:
jal x1,0xa740
Valor do imediato:
0..0 1010 0111 0100 0000 - A ordem dos bits deve ser a indicada na
Imm[ 20 | 10:1 | 11 | 19:12 ] tabela de formatos
- O bit menos significativo é omitido!
273
Exemplo 4
Codificação da instrução:
jal x1,0xa740
Valor do imediato:
0..0 1010 0111 0100 0000 - A ordem dos bits deve ser a indicada na
19:12 11 10:1 Imm[ 20 | 10:1 | 11 | 19:12 ] tabela de formatos
- O bit menos significativo é omitido!
276
Passos para a geração do executável
Linker
277
Passos para a geração do executável
Visão dos módulos
Modulo A
Legenda
Data
Instruções
Referências a dados
(variáveis) declaradas
Modulo B no módulo B
Data
Instruções
Referências a
Modulo C chamadas ao módulo C
Data
Instruções
278
Linker
Passo A: Alocação dos vários módulos em memória
Mapa de memória
Modulo A
Data
Instruções
Modulo B
Data
Instruções
Data
Data
Modulo C
Data
Data
Instruções Instruções
Instruções
Instruções
279
Linker
Passo B: Resolução das referências
Mapa de memória
Modulo A
Data
Instruções
Modulo B
Data
Instruções
Data
Data
Modulo C
Data
Data
Instruções Instruções
Instruções
Instruções
280
Executável
Instruções (programa)
Variáveis globais que devem ser inicializadas (podem haver múltiplas .data sections)
Indica os segmentos que que foram gerados pelo linker e a sua localização no ficheiro
281
Executável
Espaço de endereçamento virtual
O executável com o
programa deve ser
carregado em
Data
memória, seguindo os
endereços indicados Programa
0 Reservado (SO)
282
Passos para a geração do executável
Loader
1. Lê a estrutura do executável
2. Carrega as secções de instruções e dados
para memória
3. Copia os parâmetros de entrada para a stack
4. Inicializa alguns registos do processador (ex:
SP)
283 5. Salta para o início do programa (main)
Instruction Set Architecture (ISA)
RISC-V
→ Mapa de memória
Mapa de memória
Visão da aplicação
Memory Map
Mapeamentos a ficheiros ou a bibliotecas (libraries), p. ex.: /lib/libc.so
Segment
3GB
(User Reserva de espaço de memória alocado ao longo da execução do programa,
Space) Heap i.e., através de malloc’s
Data Variáveis globais ou variáveis declaradas dentro de funções com a keyword static
Programa Código (instruções) do programa
Reservado (SO) Código geral acrescentado pelo SO, p.ex., carregar o programa para memória e
285 0 Inicialização da stack
Mapa de memória
Bare metal, i.e., sem SO
Memória RAM
instalada no O mapa de memória do ARMv8 tem 64
RAM Dados/instruções do programa bits de endereço permitindo até 16 hexa
sistema
(ex: 16GB) bytes de memória (equivalente a 224
Terabytes de memória), mas este
espaço pode ser limitado pela
Periféricos Mapeamento dos registos dos periféricos implementação física do processador.
Kernel Space
Stack
(variáveis locais)
Memory Map
4GB Segment
Data
Periféricos
Programa
Kernel Space
Stack
(variáveis locais)
Memory Map
Segment
Heap
BSS
Data
Programa
0 Reservado (SO)
288
Mapa de memória
Divisão do mapa em páginas
Kernel Space
Página D
Stack
Cada segmento é dividida
Página C
em páginas (ex: 4kB) e
mapeado em memória
Memory Map
Segment física RAM
Página D
Página C
Heap Página A RAM 16GB
Página B
Página A Página B
Data Cada página contém informação
de apenas um segmento Periféricos
Programa
Reservado (SO) BIOS
289 0
Mapa de memória
Divisão do mapa em páginas