Lab. Microprocessadohres
PCS2031 Curso Cooperativo prof. Jorge Kinoshita.
- quadrimestre 2017
Esse calendário contém as datas referentes das aulas para as turma de quinta-feira. no dia seguinte.
Aulas
turma1: Terca 13:10-16:50H turma2: Quinta 13:30-17:10H, turma3: Sexta 13:30-17:10H
Table of Contents
- 1 Aulas
- 2 . E1: Introducao a microprocessadores, com ênfase ao ARM.
- 3 . E2: Programming Basics (cap2) + Data Processing Operations (cap3).
- 3.1 PLANEJAMENTO:
- 3.2 OBJETIVO:
- 3.3 instalar o gnuarm e ver o código em hello.s.
- 3.4 Usando o gnuarm, rode o programa da pagina 2-3 da apostila ARM Lab (item 2-2).
- 3.5 Fazer todos os exercícios do item 2.4 pagina 2-8 da apostila usando o gnuarm.
- 3.6 Estude o capítulo 3 da apostila.
- 3.7 Faca os exercicios 3.10.1 a 3.10.4 da pagina 3-11, 3-12. Seguem comentarios sobre cada exercicio.
- 3.8 Envie o codigo fonte e possiveis comentarios dos exercicios no final da aula via email, subject: labmicro cap 3A.
- 3.9 Desempenho da classe:
- 4 . E3: Data Processing Operations (cap3).
- 5 . E4: Loads and Stores (cap4)
- 6 . E5: Conditional Executiong Loops (cap5).
- 7 feriado
- 8 . E6: Subroutines (cap6)
- 9 . P1 - Subroutines (cap6)
- 10 . E7: Memory Mapped Peripherals (cap7).
- 11 . E8: C compiler + assembler - juntar C com assembly.
- 12 . E9: Hello World for bare metal
- 12.1 Planejamento:
- 12.2 Experiencia
- 12.2.1 Instale o arm-none-eabi
- 12.2.2 Rode o Simplest Bare Metal Program
- 12.2.3 Imprima "Hello World" na placa versatile emula pelo qemu
- 12.2.4 instrucao invalida em startup.s
- 12.2.5 Um Undefined Handler simples, porem errado.
- 12.2.6 A pilha no Undefined mode.
- 12.2.7 Undefined handler
- 12.2.8 modo kernel x modo usuario
- 12.3 Envie o codigo fonte e possiveis comentarios dos exercicios no final da aula via email, subject: labmicro aula 10.
- 13 . E10: interrupcao de tempo no Versatile emulado.
- 13.1 Planejamento:
- 13.2 Experiencia:
- 13.3 Geracao do código
- 13.4 Observacao sobre o codigo
- 13.5 Corrija os ERROS na apostila
- 13.6 Observe e faça pequenas alteracoes no codigo em assembly
- 13.7 Envie o codigo fonte e possiveis comentarios dos exercicios no final da aula via email, subject: labmicro aula 11.
- 14 . E11: Chaveamento entre 2 processos.
- 15 . Prova 2
- 16 Avaliacao:
1 Aulas
2 . E1: Introducao a microprocessadores, com ênfase ao ARM.
2.1 Explicar o curso, sequencia das aulas e avaliacao.
2.2 Introducão ao ARM:
http://www.ee.ic.ac.uk/t.clarke/arch/lectures/Part1.ppt www.ee.ic.ac.uk/t.clarke/arch/lectures/Part2.ppt
Modifiquei para: http://www.pcs.usp.br/~jkinoshi/2012/Part1jk.ppt
2.3 referência: ARM Laboratory Exercises, cap. 1
Ler o primeiro capítulo. Fazer exercícios 1.7.1 e 1.7.2
3 . E2: Programming Basics (cap2) + Data Processing Operations (cap3).
3.1 PLANEJAMENTO:
Para essa aula não é necessário planejamento.
3.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. cap2: todo o item 2.4: de 2.4.1 a 2.4.3
cap3: Faca de 3.10.1 ateh 3.10.4
3.3 instalar o gnuarm e ver o código em hello.s.
GCC-3.4 toolchain GNU/Linux (x86) http://www.gnuarm.com/bu-2.15_gcc-3.4.3-c-c++-java_nl-1.12.0_gi-6.1.tar.bz2 copiei em: http://www.pcs.usp.br/~jkinoshi/bu-2.15_gcc-3.4.3-c-c++-java_nl-1.12.0_gi-6.1.tar.bz2 Essa toolchain está compilada para 32 bits e foi a única toolchain que eu encontrei capaz de lidar bem com a placa evaluator7t do laboratório. Se voce quiser instalar em um linux de 64 bits terá que providenciar as bibliotecas necessárias para 32 bits.
bunzip2 bu-2.15_gcc-3.4.3-c-c++-java_nl-1.12.0_gi-6.1.tar.bz2 tar -xvf bu-2.15_gcc-3.4.3-c-c++-java_nl-1.12.0_gi-6.1.tar
No diretorio Downloads/gnuarm-3.4.3/bin estao todos os executaveis como o compilador e o debuger. Alterar o PATH:
------------------------- export PATH=$PATH PATH="$PATH:/home/manha/Downloads/gnuarm-3.4.3/bin" -------------------------
Esse novo PATH mantem-se enquanto o terminal nao for alterado. Para manter o PATH para todos os terminais abertos, voce deverah alterar o arquivo:
------------------------- ~/.bashrc -------------------------
fazendo:
------------------------- gedit ~/.bashrc -------------------------
e inserindo as linhas, tomando o cuidado de trocar home/manha para /home/terca se voce for de terca-feira e assim por diante.
------------------------- export PATH=$PATH PATH="$PATH:/home/manha/Downloads/gnuarm-3.4.3/bin" -------------------------
no fim do arquivo .bashrc.
Depois que alterar o PATH, abra uma nova aba do terminal ou um novo terminal para reexecutar o .bashrc e assim ter o PATH correto. Voce pode verificar o PATH atraves de: echo $PATH
Uma apostila que explica o ambiente GNU para a placa evaluator 7t está em: http://www.billgatliff.com/gettingStarted.html Nesse site stdio.h sumiu do hello.c:
#include <stdio.h> int a_global = 10; int foo ( int arg ) { static int foo_counts = 0; foo_counts++; return foo_counts + arg; } int main ( void ) { int nloops; char* charstr = "hello, world!\n"; for( nloops = 0; nloops < 10; nloops++ ) { printf( "%s", charstr ); foo( nloops ); } return 0; }
Nessa apostila existe o código de hello.c; um programa que apenas imprime algumas strings. Vamos fazer uma simples experiencia de gerar um executavel, sem de fato se ter a pretensao de entender o codigo. O objetivo é apenas ter um primeiro contato com o gnuarm.
Edite o código de hello.c em home/manha (/home/tarde, /home/terca, etc.). Compile:
arm-elf-gcc -Wall -g -o hello hello.c
Entre no debuger e veja ele rodando de forma simulada:
arm-elf-gdb hello (gdb) target sim (gdb) load (gdb) break main (gdb) run (gdb) continue
Uma forma mais interessante é ver através de:
arm-elf-gdb -tui hello
pois apresenta o debug junto com o código fonte em duas janelas. C-x 2 (control-x 2) abre outras janelas, para por exemplo se ver os registradores. Digite duas vezes C-x 2 para ver os registradores.
Uma outra forma de ver 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.
No curso, entretanto, vamos estudar o código assembly. O código assembly de hello.c é gerado através de:
arm-elf-gcc -S hello.c
gerando hello.s. Apenas veja o codigo, nao eh necessario entender.
O código hello.s pode gerar o hello através de:
arm-elf-gcc -Wall -g -o alo hello.s
e debugado normalente como:
arm-elf-gdb -tui alo
Para maiores informacoes sobre os comandos em si, indicamos referencias tais como: http://www.gnu.org/manual/manual.html http://www.microcross.com/gnu-arm7t-microcross.pdf http://bel.gsi.de/scripts/gnu-arm-assy-quick-ref.pdf
3.4 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 MOV r1, #20 BL firstfunc MOV r0, #0x18 LDR r1, =0x20026 SWI 0x123456 firstfunc: ADD r0, r0, r1 MOV pc, lr --------------------------------------------------
Para isso vc. pode fazer:
gedit item-2-2.s e fazer o copy and paste.
3.4.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
3.5 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.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.4.2 - 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'.
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
3.6 Estude o capítulo 3 da apostila.
3.6.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
3.7 Faca os exercicios 3.10.1 a 3.10.4 da pagina 3-11, 3-12. Seguem comentarios sobre cada exercicio.
3.7.1 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
ADD nao atualiza as flags do CPSR ADDS atualiza as flags do CPSR.
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.
3.7.2 3.10.2 - Multiplicacao de numeros
- no resultado tivemos a flag N setada, embora multiplicamos dois numeros negativos (e o resultado deveria ser positivo). Isso deve ter acontecido porque o bottom foi "negativo" e a flag foi atualizada depois do resultado.
O resultado faz sentido? Se quisermos observar o bottom (32 bits menos significativos) contendo o numero todo, temos que multiplicar numeros que caibam em representacoes de 16 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
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.
3.7.3 3.10.3 - 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
3.8 Envie o codigo fonte e possiveis comentarios dos exercicios no final da aula via email, subject: labmicro cap 3A.
3.9 Desempenho da classe:
algumas equipes nao conseguiram terminar todos os exercicios.
4 . E3: Data Processing Operations (cap3).
4.1 PLANEJAMENTO:
4.1.1 A - leiam o capitulo 3 da apostila.
4.1.2 B - Respondam as seguintes perguntas numa folha a mão (o professor fará chamada oral antes da aula).
- 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).
- 4. Escreva uma rotina que desloque um valor de 64-bits (armazenado em 2 registradores r0 e r1) de um bit para a direita.
- 5. idem 4, para a esquerda.
4.1.3 C - prepare a solucao de 3.10.7
- tragam numa folha (nao vale no computador), a solucao rascunhada a mão do exercicio de divisao 3.10.7; ou seja, como é o algoritmo da divisao. Nao eh para trazer todo o algoritmo em codigo ARM já implementado, mas se quiser coloque algumas partes em codigo ARM. 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.
4.2 OBJETIVO:
- terminar capítulo 3 da apostila. Fazer os exercicios de 3.10.5 ateh 3.10.8
4.3 DICAS e Observacoes:
4.3.1 3.10.5 -
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. Uma dica para se ter o absoluto de um numero eh fazer (zero - numero) caso o numero seja negativo. De preferencia, facam primeiro o exercicio 3.10.6 .
4.3.2 3.10.7 Division
o arm-elf-gcc nao estah compilando uma instrucao que lide com RRX como mov … RRX porem compila outras como mov … ROR
4.3.3 3.10.8
- Erro 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.
4.4 Envie o codigo fonte e possiveis comentarios dos exercicios no final da aula via email, subject: labmicro cap 3B.
4.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.
5 . E4: Loads and Stores (cap4)
5.1 PLANEJAMENTO:
5.1.1 A Leia o capitulo 4.
5.1.2 B Respondam as questoes em uma folha à mão:
B.1) Descreva o conteúdo do registrador R13 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 r13, [r0] LDRSH r13, [r0] LDR r13,[r0] LDRB r13,[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
5.1.3 C - rascunhe a solucao
Cada equipe deve trazer numa folha de papel a resposta em letra de mao (nada de coisa impressa) para a seguinte pergunta. 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).
5.2 OBJETIVO:
Fazer os exercicios do capitulo 4.
5.3 Observacoes
5.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.
5.3.2 Comentários sobre os exercícios:
- 4.5.1
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.
Declare um programa em C bem simples que contenha uma array como variável global e que fique em um loop fazendo:
x = array[5] + y
Compile o programa com a opcao -S para gerar o codigo em assembly. Observe como o assembly gerou a área de dados e como o label array foi usado no programa com instrucoes do tipo ADR. Nao se preocupe em entender todo o codigo gerado. O objetivo eh apenas observar a "cara" do assembly no mundo GNU que é diferente do assembly usado na apostila - o codewarrior.
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
- 4.5.2
Translate this C statement/assignment using the post-indexed form: array1 = array2 + 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.
- 4.5.4
Suponha que ao inves de b) initPointers (int *a, esteja escrito b) initPointers (int *array,
- 4.5.5, 4.5.6 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).
5.4 Envie o codigo fonte e possiveis comentarios dos exercicios no final da aula via email, subject: labmicro cap 4.
5.5 Desempenho da classe:
algumas turmas nao conseguiram o 4.5.6. Uma nao conseguiu o 4.5.5.
6 . E5: Conditional Executiong Loops (cap5).
6.1 PLANEJAMENTO
6.1.1 A. Leia o Capitulo 5
6.1.2 B. Responda em uma folha de papel aa mao para entregar ao professor no comeco da aula - serve de base para a chamada oral individual.
- 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.
6.1.3 C. IMPORTANTE: Fazer o rascunho de 5.5.4 em folha de papel rascunhado a mão; por exemplo, faça o diagrama de estados.
5.5.4 Finite state machines: a nonresetting sequence recognizer
- 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.
- 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 item 2 e usá-lo para resolver o item 1.
6.2 Objetivo
Fazer os exercicios do capitulo 5 da apostila em 5.5
6.3 Observacoes
6.3.1 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).
6.3.2 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.
6.3.3 5.5.4
se quiser, declare um numero binario como: 0b10101 dentro do codigo.
6.4 Envie o codigo fonte e possiveis comentarios dos exercicios no final da aula via email, subject: labmicro cap 5.
7 feriado
8 . E6: Subroutines (cap6)
8.1 PLANEJAMENTO
8.1.1 A. Ler cap 6.
8.1.2 B. Responda (rascunho no papel)
1 O que há de errado com as seguintes instruções:
a) STMIA r5!, {r5, r4, r9} b) LDMDA r2, {} STMDB r15!, [r0-r3, r4, lr}
2 Se o registrador r6 possui 0x8000 (como ponteiro para a memória); após executar
LDMIA r6,{r7,r4,r0,lr}
o que fica em r0, r4, r7 e em lr?
3 Assuma que a memória e registradores estejam:
0x8010 | 0x1 |
0x800C | 0xfeeddeaf |
0x8008 | 0x00008888 |
0x8004 | 0x12340000 |
0x8000 | 0xbabe0000 |
r0=0x13; r10xffffffff; r2 = 0xeeeeeeee; r3 0x8000
Descreva a memória e conteúdos dos registradores após a instrução:
LDMIA r3!, {r0,r1,r2}
4 Suponha que a pilha esteja como o diagrama abaixo. Que instrução seria necessária para sair do estado original e ir para o estado a), depois b) e depois c)?
Endereço | Original | A | B | C |
0x8010 | 0x1 | 0x1 | 0x1 | 0x1 |
0x800C | 0xfeeddeaf | 0xfeeddeaf | 0xfeeddeaf | 0xfeeddeaf |
0x8008 | 0xbabe2222 | 0xbabe22222 | ||
0x8004 | 0x12340000 | |||
0x8000 |
8.1.3 C. IMPORTANTE
Voce pode escolher entre:
- apresentar o codigo rodando no seu PRÓPRIO computador no comeco de aula
- ou rascunho no papel.
6.5.2 Bubble sorting 6.5.3 Magic Squares
8.2 OBJETIVO
Exercicios 6.5 do 6.5.1 ateh 6.5.4; o resto serah feito na proxima aula.
8.3 Observacoes
6.5.1 transmit the arguments by way of the stack with two subroutines, func1 and func2, that demonstrate stack functionality. É importante que o endereco de retorno seja colocado na pilha em func1.
6.5.2 Bubble Sort
- Modify your code to utilize a full descending stack. Sorting must be done on the stack only. Once the stack is sorted, store the sorted stack back to the original array of memory locations starting at 0x4001.
The algorithm for the bubble sort is as follows: a. Compare adjacent elements. If the first element is greater than the second, swap them.
b. Do this for each pair of adjacent elements, starting with the first two and ending with the last two. At this point the last element should be the greatest. c. Repeat the steps for all elements except the last one. d. Repeat this process for one fewer element each time, until you have no more pairs to compare.
Dado que eh muito confuso, nao estarei cobrando esse uso de pilha. Podem pular esse item 6.5.2.-2. Entretanto, seguem observacoes colhidas ao longo do curso. Porem, pulem esse item:
Está confuso como utilizar o full descending stack - uma forma de organizar usando pilha somente é torre de Hannoy mas usando o bubble sort estamos mexendo em elmentos de uma array. Uma idéia é: trabalha com duas estruturas - uma array onde se descobre o maior e a pilha que vai armazenando o maior elemento em cada iteracao. Observar que a array eh de bytes enquanto que a pilha eh de words (o mais simples eh desperdicar memoria ao usar os bytes como words). Outra idéia (grupo Joao) - usar duas pilhas. A pilha eh varrida a cada comparacao jogando o maior valor para a segunda pilha. Na primeira pilha sobre o menor valor. A segunda pilha com N-1 elementos é totalmente trasportada para a primeira pilha. O processo se repete para os N-1 elementos da primeira pilha.
6.5.3 Quadrado Magico Nao é necessário preocupar-se em colocar o quadrado mágico em 0x4000. É mais fácil declarar na memória ao final do programa algo como .word 1,4, … colocando as words do quadrado mágico.
6.5.4 More stacks Write ARM assembly to implement a push operation without the use of load/store multiple instructions. Write the code to handle bytes, half-words, and words. Use r0 to indicate the data type. A value of 1 in r0 indicates that a byte is to be pushed, 2 indicates a half-word, and 4 indicates a word. Put the data to push in r1.
Lembrar que sp eh sempre um multiplo de 4. Tem que tomar um certo cuidado ao empilhar byte ou half word para que o sp permaneca multiplo de 4; ou seja, dependendo do caso a memoria eh desperdicada. O mais facil eh sempre alocar 4 bytes mesmo que seja para um byte apenas.
Dica para olhar a pilha no gdb:
x/20 $sp
8.4 Envie o codigo fonte e possiveis comentarios dos exercicios no final da aula via email, subject: labmicro cap 6.
9 . P1 - Subroutines (cap6)
9.1 PLANEJAMENTO
para a prova preparem um pendrive contendo tudo o que acharem necessario para desenvolverem programas para o ARM, desde programas de experiencias passadas, livro sobre o instruction set da ARM, manuais do gdb, etc.
9.2 Prova
A prova ocorrerá na sala de laboratorio de sistemas digitais. Venham com seus laptops preparados (toolchain ou simulador instalado, codigos fonte para consulta, manuais, etc.).
9.3 prova tarde
9.3.1 pares:
dado um numero, identificar se ele é primo.
9.3.2 impares:
colocar em um vetor, na memoria, os primeiros 30 numeros primos.
9.3.3 tempo de prova
2 horas.
10 . E7: Memory Mapped Peripherals (cap7).
10.1 PLANEJAMENTO:
10.1.1 A. Leitura, alem do capt 7 da aposlita, consulte as seguintes referencias para fazer o planejamento:
- http://www.pcs.usp.br/~jkinoshi/2014/UM_KS32C50100_REV1.PDF
UMKS32C50100REV1.PDF - Manual do KS32C50100 RISC MICROCONTROLLER que está na placa do evaluator7t
- http://www.pcs.usp.br/~jkinoshi/2014/dui0134_evaluator7t.pdf
dui0134evaluator7t.pdf - Manual da placa do evaluator 7t
10.1.2 B. Rascunho de codigo
como planejamento rascunhem a solucao de cada um dos exercicios abaixo trazendo isso em PAPEL (retirarei pontos caso nao seja em papel rascunhado - nao deve ser impresso).
Os exercicios abaixo devem ser feitos com um cuidado extra mostrando como o codigo assembly faz de fato a entrada e saida, passo a passo. Nao existe informacao suficiente na apostila e por isso estou passando em anexo o manual da placa dui…pdf. Vejam o capitulo 3 - Programmer's reference do arquivo dui…pdf que contem codigo em C para o acessos dos leds, display de 7 segmentos e dip switches. Para o planejamento serah importante observar esse codigo e transpor para o assembly do ARM. O documento UMKS … eh o data sheet do ARM produzido pela Samsung. Os enderecos dos registradores estao no item 7.4.1 do ARM Lab Manual.
Se tiverem duvidas, perguntem.
Dica: Voce farah algo da seguinte forma para lidar com registradores. Como eles estao mapeados em memoria, acessamos os registradores como se estivessemos acessando a memoria normal.
- Escrevendo 0xf0 no IOPMOD: ldr r0, =0x3ff5000 @ IOPMOD ldr r2, =0xf0 @ seta 1 nos bits [7:4] str r2, [r0] @ seta IOPMOD como output
7.5.1 - Escrita nos LEDS Displaying the hex digits in binary to the surface-mounted LEDs Write ARM assembly to flash the hex digits in binary form to the surface-mounted LEDs in ascending order. Now slightly modify the code to flash the digits in descending order. Make sure to use a delay so that the digits can be seen. The digits should not stop flashing.
Para o delay crie um loop onde o registrador R0 eh inicializado com 0xfffff e eh decrementado ateh zero.
7.5.3 - Escrita no display de 7 segmentos Displaying the contents of a memory location to the seven-segment display Write ARM assembly to inspect memory location 0x4000. If the location contains a decimal number in the range 0-15, display the contents in hex on the seven-segment LED display. As an example, if 0x4000 contains 14, display an E.
7.5.5 - Leitura dos dip switches Displaying the value of the DIP switches to the surface-mounted LEDs Write ARM assembly to inspect DIP1 to DIP4, which act like four binary digits. Display the contents in binary on the surface-mounted LEDs. See Figure 2-10 of Evaluator-7T User Guide for bit assignments
10.2 OBJETIVO
Faremos os exercicios 7.5.1 a 7.5.11 envolvendo entrada/saida. Apresentam ao professor o exercicio 7.5.11 funcionando.
10.3 Observacoes
- Conexão com a placa evaluator 7t
- ttyUSB0 -> ttyS0
Para realizarmos a conexão com a placa, observe que no laboratório os computadores não possuem interface serial e sim uma interface USB/serial. O linux enxerga essa interface como o dispositivo /dev/ttyUSB0 Porém, o gnuarm 4.3 não enxerga /dev/ttyUSB0 e sim /dev/ttyS0. Criamos o script tty.sh para ligar /dev/ttyUSB0 a /dev/ttyS0; para isso primeiro ligue a placa e certifque-se de que o cabo serial está conectado. Em seguida, rode $ tty.sh aparecerá umas mensagens de erro:-> nao foi possivel resolver …
, mas a ligacao estah correta. Se por acaso voces retirarem o cabo e o reconectarem, devem ter problema pois ttyUSB0 fica inativo e teremos ttyUSB1 no linux.
- tty.sh
O script tty.sh faz o seguinte:su quinta (terca, sexta) cd /dev sudo rm ttyS0 sudo ln -s ttyUSB0 ttyS0
Altere as permissoes de ttyUSB0 para que todos possa acessar: EXAMPLE sudo chmod 666 ttyUSB0
- tty.sh
- ttyUSB0 -> ttyS0
Ao usar o arm-elf-gdb, faremos a conexao com a placa da seguinte forma:
This GDB was configured as "--host=i686-pc-linux-gnu --target=arm-elf"... (gdb) set remotebaud 57600 --> o default eh 9600 bps; se quiser, altere para 19200 38400 57600 ou 115200 caso deseje uma comuniacao mais veloz. (gdb) target rdi /dev/ttyS0 Angel Debug Monitor V1.31 (ARM, INC. Evaluator Release v1.01) Built for ARM7TDMI Serial, IRQ Built Sep 26 2000 Serial Rate: 9600 RDI_info: internal error, unimplemented message Connected to ARM RDI target.
Após conectar, nao esqueca do comando load. Use agora o arm-elf-gdb como em experiencias anteriores.
- Área de Trabalho
Nao rode o arm-elf-gdb dentro do diretório "Área de Trabalho" pois ele não conseguirá lidar com espaços no path.
- Continue x run
Apos o load, pode-se colocar breakpoints. Para rodar o codigo no kit, use c/continue e nao r/run.
- Shoud reset the target
Se após o comando target rdi /dev/ttyS0 a placa pedir para resetar o target, isso significa apertar o botao de reset 'sys' da placa evaluator7t.
- Problema ao usar o run - o gdb pergunta se quer reiniciar o programa.
Use continue ou c ao inves de run, para continuar a execucao. Ao invés de:b main run
faça
b main c
onde c = continue.
- vc. jah conectou uma vez, mas nao consegue se conectar uma segunda vez.
Provavelmente o problema estah em que o arm-elf-gdb estah segurando a porta serial. No terminal, supondo que o arm-elf-gdb nao esteja rodando, faca:ps ax | grep arm-elf-gdb
Se tiver algum processo arm-elf-gdb segurando a porta serial, faca:
killall -9 arm-elf-gdb
e tente novamente a conexao.
- Problema no STR
As portas de entrada e saida possuem tamanhos fixos: byte, word. Nao eh possivel fazer um STR (word) em uma posicao onde a porta eh um byte. Para isso use STRB.
- Problema no LDR ou ADR em posicoes como 0x3000, 0x4000
Nao use posicoes fixas como 0x3000 pois a placa evaluator7t deve ter essa posicao em EPROM ou alocada para o programa monitor. Declare um vetor ao final do seu codigo, como 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
- 7.5.3, 7.5.4
Em 7.5.3 estah escrito para usar a posicao 0x4000 de memoria. Ao inves disso, declare o que for preciso de dados no codigo em assembly como na observacao imediatamente acima. Nao use a posicao 0x3000 - o evaluator7t deve estar usando tambem essa posicao - por exemplo, ao se comunicar com o arm-elf-gdb. Os valores escritos na memoria em 0x3000 serao alterados pela placa e nao pelo seu programa. Veja observacao acima.A documentacao da placa estah errada para o display de 7 segmentos. Deveria ser algo como:
a_ g |_ |b e |_ |c d
- 7.5.6
The program must be stopped manually. Nao eh necessario que se pare o programa manualmente.