Table of Contents
- 1. . E1: Introducao a microprocessadores, com ênfase ao ARMv7.
- 2. . E2: Programming Basics (cap2) + Data Processing Operations (cap3).
- 3. . E3: Data Processing Operations (cap3).
- 4. . E4: Loads and Stores (cap4)
- 5. . E5: Conditional Executiong Loops (cap5).
- 6. . Simulado de prova
- 7. . P1 - Prova 1.
- 8. Avaliacao, Fase1:
- 9. Referências:
Lab. Microprocessadohres ; dividido em Fase1 1 e Fase 2. PCS3432 - Curso Semestral - Fase1 1 prof. Jorge Kinoshita.
1 semestre 2021
turma: Segunda 8:20-12:00H turma: Terca 8:20-12:00H
Aulas:
1 . E1: Introducao a microprocessadores, com ênfase ao ARMv7.
- 1.1. Explicar o curso, sequencia das aulas e avaliacao.
- 1.2. video sobre gnuarm, OPCIONAL
- 1.3. Instale o docker:
- 1.4. gnuarm e código "hello world" seguinte post no linux-kernel-lab.
- 1.5. Usando o gnuarm, rode o programa da pagina 2-3 da apostila ARM Lab (item 2-2).
- 1.6. video sobre o processador ARM, OPCIONAL
- 1.7. referência: ARM Laboratory Exercises, cap. 1
- 1.8. Entregue o relatorio ateh o final do dia, INDIVIDUALMENTE.
1.1 Explicar o curso, sequencia das aulas e avaliacao.
1.2 video sobre gnuarm, OPCIONAL
O seguinte video explique como criar codigo usando o gnuarm. Nao eh obrigado assisti-lo, mas se o fizer, nao gaste muito tempo com isso pois lembre-se que voce deve entregar o relatorio ateh o final da aula. Alem disso, diversos topicos serao esclarecidos durante o curso.
1.3 Instale o docker:
O docker estah instalado em sua maquina? Se sim, pule isso.
Siga: https://phoenixnap.com/kb/how-to-install-docker-on-ubuntu-18-04
Dependendo de como vc. instalar as coisas vao dar errado… por exemplo, para mim, a instalacao com snap nao funcionou; assim siga algum site como o acima, voltado para o ubuntu 18.4
Se acabou de instalar faca:
docker run hello-world
Se nao rodou, voce ainda nao deve ter permissoes. Experimente:
sudo docker run hello-world
Se nao rodou, vc nao instalou nada direito; mas se com "sudo" rodou veja: ( https://www.digitalocean.com/community/questions/how-to-fix-docker-got-permission-denied-while-trying-to-connect-to-the-docker-daemon-socket )
sudo groupadd docker sudo usermod -aG docker ${USER}
Voce terah que carregar o ambiente atraves de um reboot ou de um
su -s ${USER}
Seu usuario pertence ao grupo docker? Veja com:
groups
Teste se tudo estah certo atraves de:
docker run hello-world
1.4 gnuarm e código "hello world" seguinte post no linux-kernel-lab.
Faça com que o ARM imprima hello world de acordo com: http://linux-kernel-lab.blogspot.com.br/2018/04/basics-on-arm-processor.html Nesse post, vc. deve basicamente:
- instalar a imagem do docker que contém todo o ambiente de desenvolvimento a ser usado em nosso curso: 9.2
- rodar hello.c
Veja o seguinte video para a criacao da imagem do docker a ser usada em nosso curso:
Este video apresenta como rodar um "hello-world.c" dentro do gnuarm:
Se tiver interesse, veja as referencias 9.7, 9.8, 9.9, 9.10.
Ao rodar o gdb, veja os registradores:
(gdb) înfo registers (gdb) p $pc -> apresenta os $pc como numero decimal (gdb) p/x $r0 -> apresenta $r0 como numero hexadecimal (gdb) p/x $cpsr -> apresenta o $cpsr como numero hexadecimal.
1.4.1 Possiveis problemas ao seguir o post
- Problema de permissao ao rodar ./builddocker.sh
Este erro acontece nas maquinas do lab micro, mas nao costuma acontecer em seu computador pessoal. Para corrigir, na maquina do lab, faca:
~/gcc-arm$ sudo ./build_docker.sh
- Nao tem permissao para criar arquivo hello.c em src
Este erro acontece nas maquinas do lab micro, mas nao costuma acontecer em seu computador pessoal. Para corrigir, na maquina do lab, faca:
~/gcc-arm$ chmod 777 src
1.5 Usando o gnuarm, rode o programa da pagina 2-3 da apostila ARM Lab (item 2-2).
Observe que vc. deverá colocar o programa no formato GNU. Uma forma de fazer isso é observar o hello.s e fazer as modificacoes. Em caso de dúvidas sobre as diretivas, consulte os manuais em https://sourcery.mentor.com/sgpp/lite/arm/portal/release830; em particular consule o manual do GNU Assembler. A modificação já feita do codigo assembly do item 2-2 fica assim no gnumarm:
--------------------------------------------------- .text .globl main main: MOV r0, #15 @ comentarios vem depois de @ ou entre /* ... */ MOV r1, #20 BL firstfunc @ desvia para funcao, coloca o enderenco de retorno em R14 ou LR (link register). MOV r0, #0x18 LDR r1, =0x20026 SWI 0x123456 firstfunc: ADD r0, r0, r1 MOV pc, lr @ retorna da funcao --------------------------------------------------
Para isso vc. pode fazer:
gedit item-2-2.s e fazer o copy and paste.
Experimente trocar ADD por ADDS para ver os registradores no CPSR
--------------------------------------------------- .text .globl main main: MOV r0, #15 @ comentarios vem depois de @ ou entre /* ... */ MOV r1, #20 BL firstfunc @ desvia para funcao, coloca o enderenco de retorno em R14 ou LR (link register). MOV r0, #0x18 LDR r1, =0x20026 SWI 0x123456 @ no simulador (target sim) nao existe codigo a ser rodado quando se faz uma SWI sw. interrupt e portanto, gera erro. firstfunc: ADDS r0, r0, r1 @ O S em ADDS coloca as flags N Z C V no CPSR MOV pc, lr @ retorna da funcao --------------------------------------------------
Vamos mostrar passo a passo como compilar/montar e rodar item-2-2.s .
- Rode a image do docker. O jeito mais fácil é:
~/Downloads/gcc-arm$ ./run_docker.sh
- Compile/monte o código item-2-2.s ; o jeito mais fácil é aproveitar o alias gcc que já existe dentro da imagem:
student:~/src$ ls alo hello hello.c hello.s item-2-2.s student:~/src$ alias gcc alias gcc='arm-elf-gcc -Wall -Wextra -g' student:~/src$ gcc item-2-2.s
- Ao rodar, o arquivo a.out é gerado como saida:
student:~/src$ ls -alt |more total 500 -rwxrwxr-x 1 student student 126239 Apr 16 00:40 a.out drwxrwxrwx 2 student student 4096 Apr 16 00:40 . -rw-rw-r-- 1 student student 39 Mar 20 19:38 hello.c -rwxrwxr-x 1 student student 221628 Mar 20 19:34 alo -rw-rw-r-- 1 student student 396 Mar 20 19:31 hello.s -rwxrwxr-x 1 student student 221868 Mar 20 19:25 hello drwxr-xr-x 1 student student 4096 Mar 20 19:17 .. -rw-rw-rw- 1 student student 147 Mar 20 19:11 item-2-2.s
- Para entrar no gdb, o jeito mais fácil é usar o alias gdb:
student:~/src$ alias gdb alias gdb='arm-elf-gdb -tui --command=/home/student/.gdbinit/default' student:~/src$ gdb a.out
- Uma veze dentro do gdb,
Tecle "return" para continue até ver algo como:
│7 MOV r0, #0x18 │ │8 LDR r1, =0x20026 │ └───────────────────────────────────────────────────────────────────────────┘ sim No process In: Line: ?? PC: 0x0 Loading section .data, size 0x8a8 vma 0xa118 Loading section .eh_frame, size 0x4 vma 0xa9c0 Loading section .ctors, size 0x8 vma 0xa9c4 Loading section .dtors, size 0x8 vma 0xa9cc Loading section .jcr, size 0x4 vma 0xa9d4 Start address 0x8110 Transfer rate: 27882 bits/sec. (gdb)
- vamos nos posicionar para rodar a primeira instrucao; para isso, "break main" seguido de "run" ou de forma mais sucinta "b main" , "r" como vemos abaixo:
(gdb) b main Breakpoint 1 at 0x8218: file item-2-2.s, line 4. (gdb) r Starting program: /home/student/src/a.out Breakpoint 1, main () at item-2-2.s:4 Current language: auto; currently asm (gdb)
- agora voce já pode rodar passo a passo! Experimente usar "step" ou "next" ; de forma mais sucinta "s" ou "n". Veja que os registradores vão se modificando.
- Para sair do debug "quit" ou "q".
Veja isso ocorrendo no video:
1.5.1 Uma software interrupt
No código temos:
LDR r1, =0x20026 SWI 0x123456
que se refere a uma software interrupt pedindo um servico do monitor da placa evaluator7t. Como estamos rodando de forma simulada, essa software interrupt irá travar o gdb. Assim, nao rodem o SWI (basta colocar um breakpoint). Uma pergunta interessante é:
- qual a diferenca entre LDR e MOV? Observem que ambas as instrucoes carregaram valores imediatos nos registradores. A diferenca é que com LDR é possível carregar valores quaisquer de 32 bits enquanto que com o MOV não. Isso será importante para a questao 3.10.1
1.6 video sobre o processador ARM, OPCIONAL
Voce ainda nao tem condicoes de entender tudo o que o video explica. Muita coisa ficarah clara no decorrer do curso principalmente depois da aula sobre interrupcoes. Assim, nao gaste tempo com isso.
1.7 referência: ARM Laboratory Exercises, cap. 1
Ler o primeiro capítulo de 9.1. Fazer exercícios 1.9
1.8 Entregue o relatorio ateh o final do dia, INDIVIDUALMENTE.
- O relatorio eh para se fazer em GRUPO. Deve conter as respostas do cap 1 da apostila.
- Cada aluno recebeu a atividade de entrega do relatorio do google classroom; essa entrega eh INDIVIDUAL. Isto eh, o mesmo relatorio do grupo serah entregue várias vezes: uma para cada integrante. Caso o aluno da equipe nao entregue o relatorio, vou entender que ele nao participou do relatorio.
2 . E2: Programming Basics (cap2) + Data Processing Operations (cap3).
- 2.1. PLANEJAMENTO INDIVIDUAL (3 pontos):
- 2.2. OBJETIVO:
- 2.3. Fazer todos os exercícios do item 2.4 pagina 2-8 da apostila usando o gnuarm.
- 2.4. Estude o capítulo 3 da apostila.
- 2.5. Faca os exercicios 3.10.1 a 3.10.4 da pagina 3-11, 3-12. Dicas:
- 2.6. Entrega de relatorio e printscreen
- 2.7. Desempenho da classe:
A apostila "ARM Laboratory Exercises" roda código feito para o codewarrior/freescale e não para o gnuarm. Portanto, ADAPTEM o código da apostila para rodar no gnuarm como feito na aula passada, exemplo do item 2-2 da apostila.
2.1 PLANEJAMENTO INDIVIDUAL (3 pontos):
Leia o objetivo dessa experiencia e o cap 3 da apostila. Rode o código item-2-2.s no seu computador e acompanhe os registradores sendo modificados. Observe as flags do cspsr (apostila cap 1) ao fazer a soma. As flags são atualizadas? (Resposta: Não). Agora, no código item-2-2.s troque ADD por ADDS. As flags são atualizadas logo depois da soma (ADD)? O professor vai pedir que todos os alunos compartilhem a tela de seus computadores com esse código alterado (ADDS ao invés de ADD) do item-2-2.s no começo da aula. Quem não estiver presente perderá a nota de planejamento.
2.2 OBJETIVO:
- capítulo 2 e parte do 3 da apostila, mas ao invés de usarmos o codewarrior para windows estaremos usando o gnuarm no linux ubuntu.
Facam os seguintes exercicios da apostila e criem um relatorio com as respostas dos exercicios:
- cap2: todo o item 2.4: de 2.4.1 a 2.4.3
- cap3: Faca de 3.10.1 ateh 3.10.4 ; Veja detalhadamente as intruscoes ARM em 9.11
2.3 Fazer todos os exercícios do item 2.4 pagina 2-8 da apostila usando o gnuarm.
Observacao sobre os exercicios As perguntas do item 2.4 se referem ao codewarrior (ambiente usado pela apostila no lugar do gnuarm); por isso pensem nas questoes referindo-se ao gnuarm.
2.3.1 Exercicio 2.4.1
No ambiente codewarrior existe um make. Durante o nosso curso, nao precisaremos do make uma vez que o proprio arm-elf-gcc dispara o assembler e o linker. Para ver o que foi gerado pelo arm-elf-gcc basta fazer:
$ ls -alt|more
Esse comando coloca no topo os arquivos recentemente modificados ou criados. Apenas relatem o que foi feito - uso do arm-elf-gcc, geracao do arquivo e arm-elf-gdb para rodá-lo.
2.3.2 Exercicio 2.4.2
- step x next
A pergunta 2.4.2 pergunta sobre a diferenca entre step e stepin no codewarrior . Para o gdb, a pergunta se refere a: step: passo a passo entrando na rotina next: passo a passo mas sem entrar na rotina. Existe um problema GRAVE no uso do next. O arm-elf-gdb misteriosamente se perde ao ver um label como:
mov r0,1 label: move r0,2
Ao executar mov r0,1; o debugger nao pula para a instrucao seguinte usando next. Por isso, muito preferencialmente use 'step'.
- Problema ao executar SWI
A instrucao SWI 0x123456 eh uma interrupcao de software que roda no programa monitor que estah na flash da placa Evaluator-7T. Nós estamos simulando a execucao do codigo no gdb (target sim). O simulador nao possui o tratamento para essa interrupcao de software, por isso, coloque um breakpoint na linha onde estah a instrucao SWI (ex: linha 9) atraves de "b 9" e rode ateh lah. Dado que estamos sem monitor ou sistema operacional, estaremos sempre fazendo dessa forma: colocando um breakpoint no final do programa para observarmos se rodou ateh o final.
2.3.3 Exercicio 2.4.3
Se quisermos ver os registradores na tela do arm-elf-gdb usando C-x 2, teremos dois formatos hexa e decimal. Porém, é possível observar memória e registradores em outros formatos. Veja o manual do gdb - http://sourceware.org/gdb/download/onlinedocs/gdb/index.html Exemplos:
p/x $pc p/x $cpsr x/i $pc
Usando o help help x help p
Voce deve ter observado que x - serve para ver memoria externa.
x/d $r1
apresenta o conteudo de r1 em hexadecimal e o conteudo apontado por r1 na memoria em decimal.
p/d $r1
apresenta o conteudo de r1 em decimal.
Uma forma !!!PERIGOSA!!! de ver os bits do registrador de status eh:
p/t $cpsr
porem, os primeiros zeros serao OMITIDOS e voce pode estar vendo menos que 32 bits. Tome cuidado! Compare o cpsr com o comando "info registers". A forma segura eh:
p/x $cpsr
2.4 Estude o capítulo 3 da apostila.
2.4.1 pg 3-7:
ADD r0, r1, #0xc5, ROR 10 ver desenho na pagina 3-6.
1100 0101 para a direita em um registrador de 32 bits
depois de rodar 8 vezes temos
1100 0101 0000 … e depois de 10 vezes temos:
0011 0001 0100 …
o que fornece um o resultado da apostila:
31 40 00 00 0011 0001 0100 0000 0000 0000 0000 0000
2.5 Faca os exercicios 3.10.1 a 3.10.4 da pagina 3-11, 3-12. Dicas:
2.5.1 Desvio condicional
Para fazer os exericios, voce vai precisar de desvio condicional. Veja a tabela na apostila em: 5.2 Execution conditions . Exemplo de uso:
CMP R0,R1 BGT label
onde GT estah na tabela. Assim, podemos ter varios desvios condicionais como: BEQ, BNE e ateh mesmo BAL, mas como AL eh "default", use simplesmente "B" para o desvio incondicional. Em ARM eh possivel combinar qualquer instrucao com uma condicao. Ex: MOVEQ - move caso EQ.
2.5.2 Exercicio 3.10.1 - Signed and unsigned addition
Use LDR para carregar valores de 32 bits em registradores. Ao inves de fazer:
mov r1,#0x12345678
faça:
ldr r1,=0x12345678
- Cuidado com as flags
ADD nao atualiza as flags do CPSR; ADDS atualiza as flags do CPSR. Igualmente SUB x SUBS, MOV x MOVS, etc.
- Carry x overflow
Se representarmos numeros em 4 bits em complemento de 2, podemos representar desde o -8 ateh o 7. Ao somarmos -1 e 1 temos carry mas nao temos overflow. Somando 5+4, temos que 9>7 e portanto temos o overflow.
- signed x unsigned
Na apostila: Does their meaning change when the data values are unsigned numbers? Numa representacao de 4 bits unsigned, os numeros variam de 0 a 15. Assim, ao somarmos 7+2, obtemos 9 que pode ser representado como unsigned e nao pode ser representado em 4 bits unsigned. Assim, OVERFLOW para unsigned deve ser visto olhando a flag CARRY e a OVERFLOW em si, deixa de ter sentido.
2.5.3 Exercicio 3.10.2 - Multiplication / Multiplicacao de numeros
- no resultado tivemos a flag N setada, embora multiplicamos dois numeros negativos (e o resultado deveria ser positivo). A instrucao MULS (tem 1 L somente, nao confunda com MULLS), multiplica 2 numeros de 32 bits e coloca o resultado em um numero de 32 bits. Isso nao funciona bem. Vamos pensar em numeros de 4 bits variando de -8 a 7 em complemento de 2. Se multiplicarmos -1 e -8 em complemento de 2, temos +8. Porem, 8 nao pode ser representado em complemento de 2, 4 bits. A apostila quer mostrar que as flags foram atualizadas erradas nessa instrucao. Na verdade, nem as flags e nem o conteudo dos registradores eh confiavel dado que nao se consegue sempre multiplicar 2 numeros de 32 bits e colocar o resultado em 32 bits. O certo eh colocar o resultado em um numero de 64 bits. Para entender melhor veja no site da ARM, a especificacao da instrucao MUL: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0068b/CIHIHGGJ.html . Se quisermos observar o bottom (32 bits menos significativos) em MULS contendo o numero todo, temos que multiplicar numeros que caibam em representacoes de 16 bits.
- Why is there a need for two separate long multiply instructions, UMULL and SMULL?
Ambas as instrucoes multiplicam 2 numeros de 32 bits e colocam o resultado de 64 bits em 2 registradores: um mais signficativo e outro menos significativo. O resultado eh diferente se o numero eh signed ou unsigned. Por exemplo: pensando em multiplicar 2 numeros de 4 bits, temos no caso de 1111 = 15(unsgined) ou (-1) signed. 15*15 eh um resultado totalmente diferente de (-1) * (-1). Daih a necessidade de UMULL e SMULL. Observe que se o resultado eh colocado em 2 registradores, como R0(mais signficativo) e R1; entao apenas o bit mais significativo de R0 eh quem diz se <R0,R1> eh positivo ou negativo.
- Pequeno erro:
Obs: Na apostila ARM Lab Manual temos na pg 3-5 UMULL r6, r8, r0, r1 ; {r6,r8} = r0 × r1 onde aparentemente r6 eh o mais significativo. Pelo site da ARM temos que o r6 (primeiro argumento) eh o menos significativo.
2.5.4 Exercicio 3.10.3 - Multiplication shortcuts / Multiplicacao pelo numero 32.
- pense em algum shift.
- use MOV com deslocamento. Veja: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/BABHGAJI.html
2.5.5 Exercicio 3.10.4 Register-swap algorithm
sem problemas, exercicio simples de ser feito.
2.6 Entrega de relatorio e printscreen
Entreguem individualmente num arquivo zipado ateh o final do dia 21 de Abril, quarta-feira, (valido para as turmas de segunda e de terca).
2.6.1 - printscreen
Retorne o printscreen da tela de SEU computador referente ao exericio 3.10.4, seguindo:
Write the ARM code to implement the above algorithm, and test it with the values of A = 0xF631024C and B = 0x17539ABD . Show your instructor the contents before and after the program has run.
Nao eh necessario anexar a tela do conteudo antes de rodar o programa, apenas depois. A tela deve conter:
- seu codigo e
- os registradores depois de ter rodado o codigo.
2.6.2 código fonte de todos os itens.
Não se esqueçam de colocar no cabeçalho a forma como o código eh gerado e debugado. NAO COLOQUE ZIP DENTRO DE ZIP, ou seja, mantenha os arquivos fontes como eles estao ao inserir no zip.
- printscreen do item 3.10.4 de sua propria maquina (nao de seu colega).
2.6.3 o relatorio em PDF feito em grupo.
Nao me entreguem em .docx porque pode dar problemas ao abrir. Coloquem no relatorio as saidas ao rodarem os itens vistos. Isso pode ser em printscreen ou mesmo em texto (fonte Courier para ficar bonito) atraves de copy & paste.
2.7 Desempenho da classe:
algumas equipes nao conseguiram terminar todos os exercicios.
3 . E3: Data Processing Operations (cap3).
3.1 PLANEJAMENTO (3 pontos - apresentacao INDIVIDUAL no comeco da aula, mas discutam com sua dupla antes da aula.):
3.1.1 A - leiam o capitulo 3 da apostila.
3.1.2 B - Respondam as seguintes perguntas
- 1. O que há de errado nas seguintes instrucoes:
a. ADD r3,r7, #1023 b. SUB r11, r12, r3, LSL #32
Sugestao:
- vejam os codigos de maquinas e observem que certos numeros nao servem para fazer o codigo de maquina.
- coloquem no gnuarm e vejam o erro.
- 2. Sem usar a instrucao MUL, de as seguintes instrucoes para multiplicar o registrador R4 por:
a. 132 b. 255 c. 18 d. 16384
Dicas (apenas para pensar em como resolver os itens a,b,d,e acima):
- como vc. faria para multiplicar um valor por 4? Dica: use o MOV com o deslocamento. r1 = 4*r0
- como vc. faria para multiplicar um valor por 5? Dica: use ADD com deslocamento - r1 = r0+4*r0
- como vc. faria para multiplicar um valor por 3? r1 = r0*4 - r0; veja a diferenca entre SUB e RSB
- como vc. faria para multiplicar um numero por 15? Multiplica por 3 e depois por 5.
- 3. Escreve uma rotina que compara 2 valores de 64-bits usando somente 2 instrucoes. (dica: a segunda instrucao é condicionalmente executada, baseada no resultado da primeira comparacao).
No cap. 5 da apostila existe uma tabela com todas as condicoes possiveis. Exemplo de instrucao condicional: ADDEQ R0,R1,R2 = execute a soma se a flag Z no CPSR == 1. Alguns alunos reclamaram ser necessario consultar o cap. 5, mas nao dah para fazer o cap. 3 sem saber instrucoes condicionais (sorry!).
- 4. Escreva uma rotina que desloque um valor de 64-bits (armazenado em 2 registradores r0 e r1) de um bit para a direita.
o arm-elf-gcc nao estah compilando uma instrucao que lide com RRX como mov … RRX #1 porem compila outras como mov … ROR #1 porem, o arm-elf-gcc compila: mov … RRX ou seja, ao usar RRX jah se supoe que desloca de 1 bit para direita rodando com o carry.
- 5. idem 4, para a esquerda.
3.1.3 C - prepare a solucao de 3.10.7 (individualmente no seu computador)
- Rascunhe a solucado do exercicio de divisao 3.10.7; ou seja, como é o algoritmo da divisao. Coloque o algoritmo em codigo ARM (nao eh necessario testar). A operacao de divisao deve ser feita com shift como faz a profa. do primário e nao o algoritmo ineficiente e simples que retira um numero do outro.
Veja: http://courses.cs.vt.edu/~cs1104/Division/ShiftSubtract/Shift.Subtract.html e coloque no papel a simulacao de 1101 dividido por 10. Existe algum erro nesse algoritmo de divisao? Teste com diversos casos no proprio site antes da aula (porque existe sim um erro).
3.1.4 no comeco da aula
O professor farah uma pergunta sobre os exercicios do planejamento e pedirah que o aluno explique o algoritmo da divisao.
3.2 OBJETIVO:
- terminar capítulo 3 da apostila. Fazer os exercicios de 3.10.5 ateh 3.10.8
3.3 DICAS e Observacoes:
3.3.1 Desvio condicional
Para fazer os exericios, voce vai precisar de desvio condicional. Veja a tabela na apostila em: 5.2 Execution conditions . Exemplo de uso:
CMP R0,R1 BGT label
onde GT estah na tabela. Assim, podemos ter varios desvios condicionais como: BEQ, BNE e ateh mesmo BAL, mas como AL eh "default", use simplesmente "B" para o desvio incondicional. Em ARM eh possivel combinar qualquer instrucao com uma condicao. Ex: MOVEQ - move caso EQ.
3.3.2 Exercicio 3.10.5 - Signed multiplication
nao percam tempo com a restricao da apostila: usem instrucoes condicionais para facilitar. No cap. 5 da apostila existe uma tabela com todas as condicoes possiveis. De preferencia, facam primeiro o exercicio 3.10.6 . Pequeno erro do UMULL na apostila explicado no item 3.10.2
3.3.3 Exercicio 3.10.6 - Absolute value
Uma dica para se ter o absoluto de um numero eh fazer (zero - numero) caso o numero seja negativo.
3.3.4 Exercicio 3.10.7 Division
Teste que deve funcionar:
- 1234567 por 1234
Teste que talvez falhe:
- 123456789 por 1234
Carregue o numero no registrador com algo como:
LRD R0, =123456789
Nao precisa de se preocupar caso esteja falhando para codigos onde o bit de sinal do dividendo seja 1.
3.3.5 Exercicio 3.10.8 Gray codes
- na apostila ARM Lab Manual: A sequencia b010 011 001 000 101 111 110 100 nao eh um codigo de gray de 3 bits (ex: erro ao passar de 000 para 101 alterando dois bits). O codigo pode ser
000 001 011 010 110 111 101 100. Se tiver duvidas em como se forma o codigo gray, consulte o wikipedia.
3.4 Retorne as 4 tarefas juntas num arquivo zip:
Entreguem individualmente num arquivo zipado ateh o final do dia 28 de Abril, quarta-feira, (valido para as turmas de segunda e de terca).
3.4.1 planejamento da exp3 (em pdf, com os codigos do planejamento inclusos)
O planejamento jah foi visto no comeco da aula. Se por ventura, voce nao apresentou o planejamento ao professor (porque faltou na aula, o prof. chamou varias vezes e vc. nao respondeu, etc.), sua nota jah estah zerada. Assim, nao precisa entregar o planejamento.
3.4.2 código fonte de todos os itens da experiencia (excluindo os do planejamento).
Não se esqueçam de colocar no cabeçalho a forma como o código eh gerado e debugado. Apenas anexe os arquivos de codigo dentro do zip a ser retornado ou seja, NAO COLOQUE OS ARQUIVOS DE CODIGO ZIPADOS DENTRO DO ZIP. (1 ponto a menos se o fizer).
3.4.3 Entrega de screenshot (INDIVIDUAL)
Formato: png (ou jpg, imagem). Nao me anexe um zip com varias imagens! Entregue ateh o final da aula o screenshot do exercicio 3.10.7 - sobre a Divisao:
Write ARM assembly to perform the function of division. Registers r1 and r2 contain the dividend and divisor, r3 contains the quotient, and r5 contains the remainder. For this operation, you can either use a single shift-subtract algorithm or another more complicated one.
A divisao deve ser feita entre o seu numero USP e 1000 mostrando os registradores R1 (dividendo: seu numero USP), R2 (divisor: 1000), R3 (quociente), R5 (resto). Assim, retorne o screenshot da tela do gdb com os registradores, logo apos a divisao ter sido feita. O gdb deve estar mostrando duas telas: a tela contendo os registradores e a tela contendo o codigo. Retorne a foto (geralmente um arquivo .png) do screenshot.
3.4.4 o relatorio em PDF feito em grupo.
Nao me entreguem em .docx porque pode dar problemas ao abrir. Coloquem no relatorio as saidas ao rodarem os itens vistos. Isso pode ser em printscreen ou mesmo em texto (fonte Courier para ficar bonito) atraves de copy & paste.
3.5 Desempenho da classe:
metade das equipes nao conseguiu implementar o 3.10.8 (mas vale a pena implementar?). O 3.10.8 poderia ser visto como um exercicio extra ou ainda eliminado.
4 . E4: Loads and Stores (cap4)
4.1 PLANEJAMENTO: (3 pontos) apresentacao individual
Responda os itens abaixo e retorne a foto do que voce fez ateh no dia anterior aa aula.
4.1.1 A Leia o capitulo 4.
4.1.2 B Respondam as questoes para apresentar ao professor no comeco da aula:
B.1) Descreva o conteúdo do registrador R13 ou sp depois que as seguintes instruções forem executadas, assumindo que a memória contenha os valores mostrados abaixo. O registrador R0 contém 0x24, e o sistema de memória é little-endian (o menos significativo é colocado no endereco mais baixo).
Endereço | Conteúdo |
0x24 | 0x06 |
0x25 | 0xFC |
0x26 | 0x03 |
0x27 | 0xFF |
LDRSB sp, [r0] LDRSH sp, [r0] LDR sp,[r0] LDRB sp,[r0]
B.2) Indique se as seguintes instruções usam o modo pré ou pós indexado de endereçamento:
STR r6, [r4,#4] LDR r3, [r12], #6 LDRB r4, [r3,r2]! LDRSH r12, [r6]
B.3) Calcule o endereço efetivo das seguintes instruções se o registrador r3 = 0x4000 e o registrador r4 = 0x20
STRB r9, [r3,r4] LDRB r8,[r3,r4,LSL #3] LDR r7, [r3], r4 STRB r6, [r3], r4, ASR #2
B.4) O que há de errado na seguinte instrução? Veja "incorrect example" em: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0068b/Chdbifed.html
LDRSB r1,[r6],r3,LSL #4
4.1.3 C - rascunhe a solucao
Escreva o código em Assembly que faça:
for (i=0; i<8; i++) { a[i] = b[7-i]; }
Vai ter mais nota quem colocar o programa mais proximo da realidade; ou seja, evitem usar pseudo instrucoes. Para observar um codigo bem proximo da realidade, sugiro instalar o gnuarm na maquina de voces e testar. Procurem usar as seguintes instrucoes em seu código:
- LDR ou ADR (isto é: declarem os dados na memória e leiam de lá; por exemplo, onde comeca o a array b e a array a).
- BGE (usem instrucoes que facam o desvio condicional, nao necessariamente BGE).
- RSB (para o 7-i)
- STR (isto é: armazene de fato o dado na memória).
4.2 OBJETIVO:
Fazer os exercicios do capitulo 4.
4.3 Observacoes
4.3.1 Na apostila tem um erro no item:
4.3.1 Direct loading with MOV and MVN
MOV r0, #0x1, 30 ; r0 = 1020 32 - 30 = 2; 2 ** 2 = 4 portanto pula de 4 em 4. MOV r0, #0xFF, 28 ; r0 = 4080 32 - 28 = 4; 2 ** 4 = 16 portanto pula de 16 em 16. MOV r0, #0x1, 26 ; r0 = 4096 32 - 26 = 6; 2 ** 6 = 64 portanto pula de 64 em 64.
mas na realidade eh:
│0x8218 <main> mov r0, #4 1 *4 = 4 │ │0x821c <main+4> mov r0, #4080 255 * 16 = 4080 │ │0x8220 <main+8> mov r0, #64 ; 0x40 1 * 64 = 64.
4.3.2 Comentários sobre os exercícios:
- Exercicio 4.5.1 Assignments with operands in memory
Assignments with operands in memory Assume an array of 25 words. A compiler associates variables x and y with registers r0 and r1, respectively. Assume that the base address for the array is located in r2. Translate this C statement/assignment using the post-indexed form:
x = array[5] + y
Now try writing it using the pre-indexed form. Apenas crie um programa em assembly que use o LDR de forma pre indexada e pos indexada. Force para que os valores nos registradores caiam na posicao array + 5*4 (array de 4 bytes para cada elemento) em ambos os caso.
Uma forma simples de se declarar dados, por exemplo, uma array, estah em http://www.coranac.com/tonc/text/asm.htm :
mov r2, #1 @ Byte loads adr r0, bytes ldrb r3, bytes @ r3= bytes[0]; // r3= 0x000000FF= 255 ldrsb r3, bytes @ r3= (s8)bytes[0]; // r3= 0xFFFFFFFF= -1 ldrb r3, [r0], r2 @ r3= *r0_b++; // r3= 255, r0++; @ Halfword loads adr r0, hwords ldrh r3, hwords+2 @ r3= words[1]; // r3= 0x0000FFFF= 65535 ldrsh r3, [r0, #2] @ r3= (s16)r0_h[1]; // r3= 0xFFFFFFFF= -1 ldrh r3, [r0, r2, lsl #1] @ r3= r0_h[1]? No! Illegal instruction :( @ Byte array: u8 bytes[3]= { 0xFF, 1, 2 }; bytes: .byte 0xFF, 1, 2 @ Halfword array u16 hwords[3]= { 0xF001, 0xFFFF, 0xF112 }; .align 1 @ align to even bytes REQUIRED!!! hwords: .hword 0xF110, 0xFFFF, 0xF112
Para observar os dados na memória dentro do gdb, voce pode fazer
x/20 0x100
para ver 20 words a partir de 0x100
x/21h hwords // hwords eh o label no codigo acima
para ver 21 half words a partir do label hwords.
x/20db array // hwords eh o label no codigo acima
para ver 20 bytes em formato decimal a partir do label array
Terminando este item pule para o 4.5.2, lembrando que mais referencias estao em: http://www.coranac.com/tonc/text/asm.htm : pagina mostrando diversos codigos e dados para o gnu assembler
http://www.microcross.com/gnu-arm7t-microcross.pdf http://bel.gsi.de/scripts/gnu-arm-assy-quick-ref.pdf
e os manuais do GNU estão (por exemplo) em: https://sourcery.mentor.com/sgpp/lite/arm/portal/release830
- Exercicio 4.5.2 Loads and stores
Translate this C statement/assignment using the post-indexed form:
array[10] = array[5] + y
Now try it using the pre-indexed form.
Pergunta: qual o significado de se ter pre-indexado ou pos-indexado nesse caso? Resposta: o objetivo é apenas didático. Não tem significado. O uso do pre-indexado ou pos-indexado faz sentido dentro de um loop.
- Exercicio 4.5.4 Array assignment
Declare os elementos na memoria usando .byte e use o label ao inves de posicoes fixas como 0x4000, 0x4001, etc.
Suponha que ao inves de b) initPointers (int *a, esteja escrito b) initPointers (int *array,
- Exercicio 4.5.5 Arrays and pointers, 4.5.6 The nth Fibonacci number - sao muito parecidos.
A diferenca eh que 4.5.6 nao pede para calcular a sequencia na memoria, podendo simplesmente usar registradores para isso. Nao existe de fato muita diferenca. Alguns alunos questionaram se 4.5.6 deveria calcula f(n) para qualquer n inteiro. O primeiro problema eh que o resultado deveria caber na memória do computador e portanto n sempre terah que ser limitado: nao eh isso que vamos fazer. Assuma n limitado para resultados cabendo em byte (4.5.5) ou word (4.5.6).
4.4 Retorne as 4 tarefas juntas num arquivo zip:
Entreguem individualmente num arquivo zipado ateh o final do dia 28 de Abril, quarta-feira, (valido para as turmas de segunda e de terca).
4.4.1 planejamento da exp3 (em pdf, com os codigos do planejamento inclusos)
O planejamento jah foi visto no comeco da aula. Se por ventura, voce nao apresentou o planejamento ao professor (porque faltou na aula, o prof. chamou varias vezes e vc. nao respondeu, etc.), sua nota jah estah zerada. Assim, nao precisa entregar o planejamento.
4.4.2 código fonte de todos os itens da experiencia (excluindo os do planejamento).
Não se esqueçam de colocar no cabeçalho a forma como o código eh gerado e debugado. Apenas anexe os arquivos de codigo dentro do zip a ser retornado ou seja, NAO COLOQUE OS ARQUIVOS DE CODIGO ZIPADOS DENTRO DO ZIP. (1 ponto a menos se o fizer).
4.4.3 Entrega de screenshot (INDIVIDUAL)
Formato: png (ou jpg, imagem). Nao me anexe um zip com varias imagens! Entregue ateh o final da aula o screenshot do exercicio:
4.5.5 The Fibonacci sequence
com a serie de Fibonacci na memoria com o numero de termos correspondente ao ultimo digito de seu numero USP.
4.4.4 o relatorio em PDF feito em grupo.
Nao me entreguem em .docx porque pode dar problemas ao abrir. Coloquem no relatorio as saidas ao rodarem os itens vistos. Isso pode ser em printscreen ou mesmo em texto (fonte Courier para ficar bonito) atraves de copy & paste.
5 . E5: Conditional Executiong Loops (cap5).
5.1 PLANEJAMENTO (3 pontos)- individual
5.1.1 A. Leia o Capitulo 5
5.1.2 B. Responda:
- 1. Traduza as seguintes instrucoes em uma unica instrucao ARM:
- a. adicione resgistradores r3 e r6 somente se N = 0 (N estah "clear"). Armazene o resultado no registrador r7.
- b. adicione resgistradores r3 e r6 somente se N = 1. Armazene o resultado no registrador r7.
- c. Multiplique os registradores r7 e r12, colocando os resulados no registrador r3 somente se C estah setado (C = 1) e Z = 0 (apostila estah com erro, ver http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0024a/CHDEEABE.html).
- d. Multiplique os registradores r7 e r12, colocando os resulados no registrador r3 somente se C clear ou Z set .
- e. Compare os registradores r6 e r8 somente se Z estah zerado.
- f. Compare os registradores r6 e r8 somente se Z set ou N ≠ V
- Observe a seguinte funcao em C:
int foo(int x, int y) { if ((x + y) >= 0) return 0; else return 1; }
Suponha que ela tenha sido compilada e traduzida no seguinte codigo:
foo ADDS r0,r0,r1 BPL PosOrZ done MOV r0, #0 MOV pc, lr PosOrZ MOV r0,#1 B done
O compilador gerou o código corretamente? O compilador retorna 0 ou 1 em r0. Se não está bom o código, corrija. Altere o código para que ele execute a funcao em somente 4 instrucoes (dica: use execucao condicional).
- a. adicione resgistradores r3 e r6 somente se N = 0 (N estah "clear"). Armazene o resultado no registrador r7.
5.1.3 C. IMPORTANTE: Fazer o rascunho de 5.5.4 ; por exemplo, faça o diagrama de estados.
5.5.4 Finite state machines: a nonresetting sequence recognizer
- Exercicio 5.5.4 1. Consider an FSM with one input X and one output Z. The FSM asserts its output Z when it recognizes an input bit sequence of b1011. The machine keeps checking for the sequence and does not reset when it recognizes the sequence. Here is an example input string X and its output Z:
X = ...0010110110... Z = ...0000010010...
Write ARM assembly to implement the sequence recognizer. Start with the initial input X in r1. Finish with the output Z in r2 at the end of the program.
- Exercicio 5.5.4 2. Now write the code to recognize any sequence Y up to 32 bits. Start with the recognizing sequence Y in r8 and the size of Y in r9. For example, to recognize the sequence Y = b0110110, then r8 = 0x36 and r9 = 0x7 before program execution. Everything else should be the same is in Step 1. Make sure that your program works for every case, including the case when r9 = 1 or r9 = 32.
Uma idéia é fazer o 5.5.4 item 2 e usá-lo para resolver o item 1, nesse caso, pense se de fato precisa de uma maquina de estados.
5.2 Objetivo
Fazer os exercicios do capitulo 5 da apostila em 5.5
5.3 Observacoes
5.3.1 Exercicio 5.5.2
Se vc. considerar que nao eh necessario usar MOVNE, delete essa instrucao do codigo sugerido. (mas talvez precise sim - um registrador nao pode ser origem e destino na multiplicacao).
5.3.2 Exercicio 5.5.3
- Find maximum value
In this exercise, you are to find the largest integer in a series of 32-bit unsigned integers. The length of the series is determined by the value in register r5. The maximum value is stored in the memory location 0x5000 at the end of the routine. The data values begin at memory location 0x5006. Choose 11 or more integers to use. Use as much conditional execution as possible when writing the code. Demonstrate the program to your lab instructor and print out the memory space starting at 0x5000 before and after the program runs. Be sure to include enough memory space to show all of your 32-bit integer values.
0x5006 não é múltiplo de 4 - as words devem estar alinhadas em múltiplos de 4. Apenas declare as words (valor maximo e sequencia de words) em seu codigo e deixe que o gnuarm escolha suas posicoes.
- Obs: A apostila foi escrita para o codewarrior e estamos usando o gnuarm e nesse ambiente é razoavelmente simples definir toda uma área de dados em uma certa posição de memória (no ldscript), mas não é simples definir que dados sejam alocados em um endereço específico - para isso podemos usar ponteiros para a posição fixa.
Nesse laboratório, ao invés de usar 0x5000, defina uma área de dados de 100 bytes assim:
dados: .space 100
e no programa podemos fazer, por exemplo:
LDR r0,=dados+4
e dessa forma não dependemos da posição fixa 0x5000 Caso queira dados jah pre-inicializados faca:
dados: .word 0x1, 0x2 ...
- Obs: A apostila foi escrita para o codewarrior e estamos usando o gnuarm e nesse ambiente é razoavelmente simples definir toda uma área de dados em uma certa posição de memória (no ldscript), mas não é simples definir que dados sejam alocados em um endereço específico - para isso podemos usar ponteiros para a posição fixa.
5.3.3 Exercicio 5.5.4
se quiser, declare um numero binario como: 0b10101 dentro do codigo.
5.4 Envie respondendo aas tarefas do google classroom.
5.4.1 Entrega dos arquivos fontes (feito em grupo, entrega individual)
- Entregue no dia da aula os codigos fontes de cada exercicio anexando o arquivo um a um. NAO ZIPEM. No cabecalho de cada codigo, escreva como o arquivo deve ser gerado. Comente o codigo para voce mesmo entender na hora da prova. Caso tenha feito algum script para geracao do codigo (recomendado), anexe o script em seu codigo. Embora o codigo seja feito em grupo, a entrega eh INDIVDUAL.
5.4.2 Entrega de E5 relatorio (feito em grupo, entrega individual)
Formato: pdf. Entregue o relatorio (pdf) cada exercicio por seu grupo, com o codigo e screenshot da tela do gdb. Embora o relatorio seja feito em grupo, a entrega eh INDIVDUAL.
5.4.3 Entrega de screenshot (INDIVIDUAL)
Apresente o printscreen de 5.5.4 item 2 com X (R1) = 0x5555AAAA Y (R8) = 5 (padrao em binario = 0b101) nbits do padrao (R9) = 3 Apresente em seu printscreen as posicoes onde o padrao foi encontrado Z (R2).
6 . Simulado de prova
6.1 PLANEJAMENTO; (sem entrega).
Para a prova revise todas as experiencias. Certifique-se de que voce eh capaz de consultar rapidamente todo o codigo de todas as experiencias, principalmente a rotina da divisao da E3. Certique-se de que a rotina de divisao estah funcionando e que voce eh capaz de usah-la. Certifique-se de que eh capaz de fazer a "Amostra de uma prova simples" logo abaixo.
6.2 Prova/simulado
Os alunos receberao a prova (atividade do google classroom) via email e devem entregah-la em no maximo 2:00H como retorno da tarefa no google classroom. O tempo de retorno estarah sendo contabilizado na prova de forma que se a entrega de tudo funcionando (sbumissao no google classroom) for:
- 0-0:30H - nota 10
- 0:30-2:00H - nota caindo linearmente de 10 a 7.
- 2:00H ou um pouco mais - menor que 5.
6.3 Amostra de uma prova simples
dado um numero, identificar se ele é primo.
6.3.1 tempo de prova
2 horas.
7 . P1 - Prova 1.
8 Avaliacao, Fase1:
Nota Final = (Fase1 + Fase2)/2
Fase1 = (E2+E3+E4+E5)/4 * 0.2 + 0.8 * P1
8.1 Avaliação por experiência:
- apresentação do planejamento no começo da aula na máquina do aluno. O aluno perderá 3 pontos caso não apresente o planejamento ao professor logo no começo da aula, quando o professor visitar a sua equipe. Portanto, apresentem-se à aula pontualmente.
- durante a aula, o professor visitará cada uma das equipes (que estarão em suas salas separadas) pedindo que cada aluno mostre como está andando na experiência compartilhando a tela de seu computador no google meets. Caso um aluno não possa mostrar a tela do seu computador na visita do professor, perderá pelo menos um ponto por não estar presente; caso isso se repita cinco vezes, o professor considerará que o aluno de fato não estava presente na aula (mesmo que esteja com o computador ligado conectado no google meet) e assim, ele perderá a nota da experiência (nota = zero).
- Como retorno da atividade do google classroom, entregar o código, relatório, em grupo com o screenshot da tela do computador de cada aluno pedido. Coloquem no cabecalho de cada arquivo fonte a forma como o programa final é gerado. Isso vai ser muito importante para voces mesmo na hora da prova!
- A nota por experiencia eh composta de: planejamento (3 pontos), visita do professor+retorno da atividade no google classroom (7 pontos). O retorno da atividade pode ser feito até o final do dia da experiencia.