AULA 5 - Microprocessadores - Graduação: mudanças entre as edições

De IFSC
Ir para navegação Ir para pesquisar
imported>Fargoud
imported>Fargoud
Linha 548: Linha 548:


<table class="wikitable" style="text-align: center; color: green;">
<table class="wikitable" style="text-align: center">
   <tr>
   <tr>
     <th class="tg-yw4l">0xFFFFFFFF-0xE0000000</th>
     <th class="tg-yw4l">0xFFFFFFFF-0xE0000000</td>
     <th class="tg-yw4l">Periféricos do sistema: NVIC, debug</th>
     <th class="tg-yw4l">Periféricos do sistema: NVIC, debug</th>
   </tr>
   </tr>

Edição das 08h09min de 10 de abril de 2018

CONJUNTOS DE INSTRUÇÕES

Um programador de linguagem de alto nível normalmente conhece muito pouco acerca da arquitetura da máquina que está usando.

O conjunto de instruções da máquina é o limite em que o projetista de CPU e o programador de baixo nível enxergam, da mesma máquina.

Implementar uma CPU é uma tarefa que envolve, em grande parte, implementar um conjunto de instruções de máquina.

Já programar em linguagem de máquina (na verdade, em linguagem de montagem, Assembly) exige um conhecimento acerca do conjunto de registradores da CPU, a estrutura de memória, os tipos de dados disponíveis na máquina e o funcionamento da ULA.

Porém, da descrição do conjunto de instruções à uma compreensão sobre o funcionamento da CPU, há um longo caminho.

CARACTERÍSTICAS DE INSTRUÇÕES DE MÁQUINA

A operação de uma CPU é determinada pelas instruções que ela executa, conhecidas como instruções de máquina.

A coleção de instruções que uma determinada CPU é capaz de executar é conhecida como conjunto de instruções da CPU.

Elementos de instrução de máquina

Cada instrução deve conter toda a informação necessária para que a CPU possa executá-la.

MIPcicloinst.png

A figura acima ajuda a definir os elementos da instrução:

  • Código de operação (OPCODE) - Especifica a operação a ser efetuada (por exemplo, ADD, ou E/S, etc). A operação é especificada por um código binário.
  • Referência a operando fonte - a operação pode envolver um ou mais operandos fonte, ou seja, que constituem dados de entrada para a operação.

Exemplos:

    • operação com um único operando: INV(A)
    • operação com dois operandos: ADD(A,B)
    • operação com três ou mais operandos: DEV(GE(A,B),C,D)
  • Referência a um operando de destino - a operação pode eventualmente produzir um resultado, que deverá ser enviado a um endereço de memória, ou registrador
  • Endereço da próxima instrução - indica aonde a CPU deve buscar a próxima instrução (memória principal ou virtual), depois que a instrução corrente for completada, quando for o caso.

Os operandos fonte e destino podem estar localizados em:

  • Memória principal ou virtual - implica em busca na memória RAM, ou no HD (quando virtual)
  • Registrador da CPU - se houver apenas um registrador, a referência a ele poderá ser implícita. Quando há acumulador, a referência a ele é default. Caso hajam vários registradores, normalmente a referência a cada um, individualmente, é feita por um número inteiro correspondente.
  • Dispositivo de E/S - indicado diretamente na instrução. Se for usada a E/S mapeada na memória, esta informação se resumirá a um endereço de memória, como os demais. Pode ser também um registrador específico (Ex: porta serial).

REPRESENTAÇÃO DE INSTRUÇÕES

Internamente, cada instrução é representada por uma sequência de bits.

É dividida em campos, correspondentes aos elementos da instrução.

Exemplos:

MIPformatinst.png


MIPformatinstias.png
MIPinstarm.png

A maioria das CPUs têm mais de um formato de instrução.

Durante a execução, uma instrução é lida em um registrador de instruções (IR) da CPU. A CPU extrai os dados dos vários campos da instrução e efetua a operação correspondente.

Os códigos de operação normalmente são representados por abreviações, chamadas mnemônicos, que evitam que os programadores tenham que trabalhar diretamente com valores binários.

Alguns exemplos mais comuns são:

ADD  -------------  Adição
SUB  -------------  Subtração
MPY  -------------  Multiplição
DIV  -------------  Divisão
GT   -------------  Operação >
LT   -------------  Operação <
GE   -------------  Operação ≥
LE   -------------  Operação ≤

Os operandos também são representados por símbolos.

Por exemplo:

  ADD R, Y

pode significar adicionar o valor contido na posição Y, com o valor contido no registrador R. Neste caso, Y é um endereço de memória e R, um registrador da própria CPU.

NÚMERO DE ENDEREÇOS

Uma das maneiras tradicionais de se descrever uma arquitetura é em termos do número de endereços contidos em cada instrução.

Obviamente, instruções aritméticas e lógicas requerem um número maior de operandos (e de endereços, por conseguinte). Normalmente, precisam de dois operandos que serão submetidos a um cálculo ou comparação, e de um terceiro, pra armazenar o resultado.

O endereço da próxima instrução normalmente é implícito, armazenado no registrador PC.

A figura abaixo compara o que seriam instruções típicas de um, dois ou três endereços, para computar a mesma linha de programação:

Y = (A - B) / (C + D x E)
MIPinstrxend.png

Note que as instruções com 3 endereços implementaram o comando com apenas 4 instruções de máquina. Porém, instruções de 3 endereços não são muito comuns, porque implicam em instruções grandes.

No caso das instruções de 2 endereços, foram necessárias 6 linhas de código, duas a mais, portanto. Nestas instruções é típico que um dos endereços referencie tanto o operando, quanto o resultado. Gera opcodes menores, porém gera códigos maiores e exige maior habilidade do programador.

As instruções de 1 único endereço exigem que um segundo endereço seja sempre implícito (normalmente, o Acumulador - AC). Neste caso, foram necessárias 8 instruções para resolver o problema.

É possível também usar-se em expressões aritméticas uma instrução com ZERO endereço. Neste caso, é necessária uma organização de memória especial, chamada pilha. As instruções com zero endereço sempre referenciam os valores nas duas posições no topo da pilha.

NÚMERO DE ENDEREÇOS Representação simbólica Interpretação
3 OP A, B, C A ← B OP C
2 OP A, B A ← A OP B
1 OP A AC ← AC OP A
0 OP T ← (T-1) OP T


Além de tudo que foi citado, as instruções podem variar muito de tamanho porque o endereço em questão de cada operando pode se referir à memória física ou a um dos registradores da CPU. Como as memórias são muito maiores que o número de registradores, vão utilizar endereços muito mais longos.

Assim, existem máquinas que, quando vão endereçar um valor NA MEMÓRIA externa (RAM) utilizam mais de uma instrução para acessar o dado.

Tudo sempre vai depender da arquitetura da máquina.


TIPO DE INSTRUÇÃO

Como já vimos, uma única instrução escrita em linguagem de alto nível pode requerer várias instruções de máquina.

Os tipos de instrução de máquina que existem são:

  • Processamento de dados - instruções aritméticas e lógicas
  • Armazenamento/transferência de dados - instruções de memória
  • Movimentação de dados - instruções de E/S
  • Controle - instruções de teste e de desvio
MIPtiposinst.png
MIPtiposinst2.png

Na maioria das vezes, as instruções são auto-explicativas.

As instruções do tipo transferência de controle, no entanto, podem ser muito complexas. Em todos os casos, exceto com elas a próxima instrução a ser executada é aquele que segue imediatamente a atual, na memória.

Nas instruções de transferência de controle, a CPU atualiza o PC com o endereço de alguma outra instrução, armazenada na memória de programa.

As instruções de transferência de controle são aquelas utilizadas quando há loops no código, ou comandos de decisão ou ainda quando o código teve que ser segmentado em vários arquivos, normalmente porque estava muito extenso.

Instruções de desvio

Nestas, um dos operandos é o endereço da próxima instrução a ser executada.

Com frequência, essa instrução é do tipo desvio condicional, isto é, o desvio só ocorrerá se uma determinada condição for satisfeita. Caso contrário, o programa segue com a próxima instrução adjacente, sem alterações no PC além do incremento normal.

Estas instruções normalmente têm o nome de BRANCH ou JUMP e podem depender de uma condição, ou ser incondicionais.

Exemplo:

MIPbranch.png

Instruções de Chamada de procedimento

Um procedimento, ou função, ou ainda subrotina é um trecho de código independente que modulariza um programa.

O mecanismo de controle de procedimentos envolve duas instruções básicas: uma instrução de chamada, que desvia a instrução corrente para o início do procedimento, e uma instrução de retorno, que provoca o retorno da execução para o endereço onde ocorreu a chamada. Ambas são condições de desvio.

A figura abaixo ilustra o uso de procedimentos na execução de um programa.

MIPproceds.png

INSTRUÇÕES DO PENTIUM II E DO POWERPC

Para exemplificar, apresentamos o caso especial de conjunto de instruções de um processador de propósito geral que foi muito utilizado até o início da década de (20)00.

MIPconjp21.png
MIPconjp22.png
MIPconjp23.png

CONJUNTO DE INSTRUÇÕES DO ARM

O conjunto de instruções também é chamado de "ISA - Instruction Set Architecture".


MIPinstARM1.png

A arquitetura ARM trabalha com três tipos de instruções: o ARM, THUMB e o THUMB-2.

O conjunto THUMB de instruções de 16 bits trabalha com registradores de 32 bits.

O código THUMB é capaz de reduzir em até 65% o tamanho de um código ARM (maior densidade de código), e aumentar em até 160% o desempenho, em relação a um processador ARM equivalente, conectado a um sistema de 16 bits, apenas.

MIPinstARM4.png

Características do ISA Arm

  • 13 registradores de propósito geral:
    • R0 a R7 (low registers)
    • R8 a R12 (high registers)
  • 3 registradores de uso/significado especial
    • r13: stack pointer (SP)
    • r14: link (LR)
    • r15: (PC)
  • 1 registrador de propósito especial
    • xPSR = Program Status Register
  • Registradores xPSR, PC, LR, R12, R3, R2, R1 e R0 são armazenados automaticamente na pilha quando uma interrupção ocorre.
MIPregsARM.png
MIPregsARM2.png
  • Arquitetura load-store: as instruções somente lidam com valores que estejam nos registradores (ou imediatos) e sempre armazenam resultados em algum registrador. O acesso à memória é feito apenas através das instruções load (para carregar o valor da memória em um registrador) e store (para armazenar o valor de um registrador na memória).
  • Permite a execução condicional de várias instruções.
  • Máquina de 3 endereços – dois registradores operandos e um registrador de resultado são especificados.
    • 1º operando: especifica o local onde será armazenado o resultado da operação.
    • Outros: valores imediatos ou locais onde se encontram os dados.
 Exemplo: ADD R1, R2, #4 
  R1 ← (R2) + 4
  • Uniformidade e tamanhos fixos dos campos das instruções para facilitar a decodificação.
  • I/O mapeado em memória: a comunicação com dispositivos periféricos é feita no próprio espaço de endereçamento de memória (via load e store).
  • Endereços de memória se referem a bytes individuais.


Formato de instruções

Apesar das diferenças entre as instruções, os projetistas mantiveram certa regularidade no formato delas, facilitando a decodificação. O formato geral é do bit menos significativo ao mais significativo, o seguinte:

  • 4 bits para condição de execução;
  • 3 bits para o tipo de instrução;
  • 5 bits para o opcode;
  • 20 bits, cujo uso e repartição varia para acomodar endereços, referências a registradores,

deslocamentos e rotações.

Operandos:

Registradores:

ADD r1, r2, r3
MOV r1, r2

Imediatos: identificados pelo símbolo #

ADD r1, r2, #10
MOV r1, #0


Maiores detalhes sobre o formato das instruções podem ser vistos na figura.

MIPinstARM16.png


Estas condições são ativadas através de sufixos que são colocados junto com os minemônicos das instruções.

Por exemplo, um salto (B) pode ser acompanhado de um NE (not equal), o que gera uma expressão BNE.

Essa instrução só será executada caso a condição seja verdadeira.


Tipos de instruções

Quanto ao número de bits, as instruções podem ser dos seguintes tipos:

ARM

MIPinstARM5.png


THUMB

  • Operações de 32 bits, em instruções de 16 bits
  • Introduzido no processador ARM7TDMI (Datasheet)
  • Suportado por todos os processadores ARM, desde então


THUMB-2

  • Permite uma mistura com performance otimizada de instruções de 16/32 bits
  • Todas as operações do processador podem ser realizadas no estado "Thumb"
  • Suportado por todos os processadores da linha Cortex-M, desde então.
MIPinstARM12.png


Quanto ao tipo de operação, tipos de instruções oferecidos são:

  • Load/Store: Instruções de carregamento e escrita de dados na memória. Podem ler/escrever

palavras inteiras(32 bits), meias-palavras(16 bits), bytes sem sinal, e podem ler e estender o sinal de meias-palavras.

A arquitetura ARM suporta dois tipos de instruções de load e store que transferem o conteudo de um registrador para a memória ou ao contrário.

O primeiro tipo pode carregar ou escrever uma parava de 32 bits ou um byte sem sinal.

O segundo tipo pode ler ou escrever meia palavra de 16 bit sem sinal, e pode carregar e sinalizar meia palavra de 16 bit ou um byte. Este tipo de instrução está disponível apenas para a arquitetura ARM versão 4 ou posterior.

MIPloadst.png
  • Load/Store em blocos: são instruções que permitem definir a leitura/escrita de blocos de até 16 registradores em uma única instrução. Isso é feito com uma máscara de 16 bits na instrução

que define quais registradores serão usados, e permite atingir uma banda de comunicação quatro vezes maior do que uma instrução que usa um único registrador. Essas instruções podem ser usadas para início e retorno de chamadas, assim como para ler blocos de memória.


  • Desvio: Todos os processadores ARM suportam instruções de branch com saltos condicionais para frente ou para trás de até 32M. A condição é dada por um campo de 4 bits. Saltos mais longos podem ser feitos através de chamadas de subrotinas como por exemplo o Branch whith Link (BL), que mantem o endereço de retorno no LR (R14).


  • Processamento de Dados: são operações de adição e subtração, operações lógicas AND, OR e

XOR, e instruções de comparação e teste;

    • Multiplicação de inteiros: as multiplicações de inteiros podem ser feitas com operandos de 32 ou 16 bits, e o resultado pode ocupar 32 ou 64 bits;
    • Adição/Subtração paralelas: essas instruções permitem aplicar a operação em partes dos operandos, de forma paralela.

Um exemplo é a instrução ADD16, que adiciona as primeiras meias-palavras dos operandos para formar a meia palavra superior do resultado, enquanto faz o mesmo com as meias-palavras inferiores para formar a parte inferior do resultado. Essas instruções são úteis para processamento de imagens

MIPinstrpd.png
MIPinstrpd2.png
  • Extensão: são instruções para reagrupar dados;
  • Acesso a registrador de estado: é permitido ler e escrever em partes do registrador de estados. Existem duas instruções para mover os conteúdos de um registrador de propósito geral e de um registrador de estado, que são as seguintes:
    • MRS – move o conteúdo do registrador de estado para um registrador de propósito geral.
    • MSR – move o conteúdo do registrador de propósito para um registrador de estado.
  • Interface para coprocessadores: há um grupo de instruções para trocas de dados com coprocessadores, assim como para controle destes. Elas permitem ao processador ARM iniciar uma operação de processamento de um coprocessador. Permite fazer transferências entre os registradores do processador e dos coprocessadores. Permitem também o processador criar endereços para o coprocessador carregar e escrever instruções. Todo o tratamento de ponto flutuante é feito por um coprocessador, cuja presença nos chips é opcional.
  • Intercâmbio com Thumb: são instruções para indicar se serão executadas instruções de 32 ou 16 bits. A instrução BX permite a troca entre o estado ARM e o estado THUMB. Esta instrução copia o conteúdo de um registrador de propósito geral para o PC. Caso o bit[0] do valor transferido para o PC seja 1, o processador troca para o estado THUMB.
  • instruções geradoras de exceções. Existe duas instruções deste tipo:
    • a SWI que causa uma interrupção de software. É o mecanismo principal utilizado pelo ARM para poder executar códigos do Sistema Operacional no modo de usuário (User Mode).
    • E existe o BKPT. Esta instrução é usada para breakpoints na arquitetura ARM da versão 5 em diante.

 

O CONJUNTO DE INSTRUÇÕES THUMB

O THUMB possui instruções com as mesmas finalidades das instruções ARM, porém são codificadas com 16 bits.

Estas instruções THUMB geram códigos menores porém muitas vezes ocorre de aumentar o número de instruções que o processador deve executar.

Uma solução para isso são aplicações que utilizam ambos tipos de instruções (ARM e THUMB).

Aplicações deste tipo conseguem reduzir o tamanho do seu código significativamente e conseguem manter o consumo de energia baixo.

As codificações de algumas instruções THUMB são as seguintes:


As instruções a seguir se referem às adições do conjunto de instruções "thumb2" do ARM (que alem de implementar as instruções de 16 bits no formato "thumb", acrescentou novas instruções de 32 bits ao conjunto padrão de instruções do ARM).

Apenas as mais interessantes para a disciplina foram relacionadas. Para cada instrução colocamos o mnemônico, descrição, e o número da página correspondente no manual detalhado de instruções:

  • BFC - Bit field clear p-89
  • BFI - Bit field insert p-89
  • BIC - Bit Clear - p-75
  • CBZ/CBNZ - Compare and branch if zero/non zero - p93
  • CLZ - Count leading zeros - p-78
  • NOP - nop - p-102
  • ORN - Logical OR NOT - p-75
  • RBIT - Reverse bits - p-81
  • REV - Reverse byte order in a word - p-81 (passa uma palavre de "little endian" para "big endian" e vice-versa)
  • SXTB - Sign extend a byte - p-90
  • TBB - Table branch byte - p-96
  • UDIV - Unsigned divide - p-86
  • UMULL - Unsigned multiply (32x32), 64 bit result
  • UXTB - Zero extend a byte - p-90
  • CPSID/CPSIE - Interrupts Disable/Enable - p-98


Instruções de deslocamento

As instruções a seguir são, na verdade, sinônimos para a instrução

MOV Rd, Rd, XXX #n 

onde XXX é um dentre LSR, LSL, ASR, ROR e n é uma constante variando de 0-31.

Obs: se o sufixo S for acrecentado a XXX então o último bit deslocado de Rd entra no bit C (Carry) da palavra de estado.


Obs: os bits de uma palavra são numerados de 0 a 31, do menos significativo ao mais significativo

LSR Rd, #n  - desloca Rd n bits para a direita inserindo n 0s à esquerda (divide Rd por 2**n)
LSL Rd, #n  - desloca Rd n bits para a esquerda inserindo n 0s à direita (multiplica Rd por 2**n)
ASR Rd, #n  - desloca Rd n bits para a direita, replicando o bit 31 (preserva o bit de sinal)
                   - divide um inteiro com sinal por 2**n
ROR Rd, #n  - rotaciona para a direita n bits de Rd (o bit 0, - significativo, entra no lugar do bit 31)

XXX Rd, Rm,#n - variante permitida das instruções acima; Rm não muda

       RRX Rd, Rm  - rotaciona um bit do par (Rm,C) como se fosse uma palavra de 33 bits:  Rd0->C, C->Rd31, etc 
                   - resultado vai para Rd, Rm não é alterado, exceto se Rd=Rm.

Execução condicional de instruções

As instruções lógico-aritméticas podem ser condicionalmente executadas dependendo dos flags da palavra de estado que foram atualizados numa instrução anterior (usualmente imediatamente anterior).

Existem 15 condições que podem ser usadas como sufixo da instrução, e que são as mesmas usadas nas instruções de salto condicional:

eq, ne, cs ou hs, cc ou lo, mi, pl, vs, vc, hi, ls, ge, lt, gt, le, al. 

Para que a execução condicional seja possível até 4 instruções devem ser precedidas pela instrução especial "If-Then condition instruction":

  it cond, 

onde cond é uma das 15 siglas de 2 letrasi citadas anteriormente (existem outros 3 possíveis parâmetros).

Exemplos:

(1) suponha que r1 contem um inteiro com sinal: colocar em r0 o valor absoluto desse inteiro:

movs r0, r1	@ atualiza flags
it mi		@ queremos tomar o negativo caso r0 <0
rsbmi r0, #0    @ faça r0 := 0 - r0 caso o bit N estivesse ligado

(2) algoritmo para calcular o máximo divisor comum de dois inteiros em r1 e r2, devolvendo o resultado em r1 e r2:

loop:   cmp  r1, r2         @ cmp sempre atualiza flags 
 it gt               @ queremos testar se r1 > r2
 subgt r1, r2        @ se r1 > r2, faça r1:=r1-r2 
 it lt               @ senão teste por <
 sublt  r2, r1       @ se r1 < r2 faça  r2:= r2 -r1
 bne  loop           @ se r1 # r2 volte ao laço

@ senão mdc=r1=r2

Estrutura de Procedures e Functions (De C para Assembler)

A chamada de funções e procedures é dividida em 6 passos:

1º Passo: Parâmetros

As funções de até 4 parâmetros tem como destino os registradores de R0-R3 , com o primeiro parâmetro no r0. Os demais são colocados na pilha e são acessados utilizando [SP+Displacement].

void func1 (

 long  b,     //Primeiro parâmetro passado em R0
 int  *c,     //Segundo parâmetro passado em R1
 short d,     //Quarto parâmetro passado em R2
 float e)     //Quinto parâmetro passado em R3

No caso acima, todos os argumentos cabem nos registradores.

void func2 (

 long long f,  //Primeiro parâmetro passado em R0/R1          
 int g,        //Segundo parâmetro passado em R2    
 double h)     //Terceiro parâmetro passado em R3 e Pilha
 long i)       //Quarto parâmetro passado somente na Pilha

Já aqui, os primeiros dois são passados nos registradores, o terceiro é passado parcialmente no registrador e o quarto é passado diretamente na pilha.

2º Passo: Chamada

É chamada executando o comando de Branch and Link (Expansão e linkagem).

BL minhafunção

3º Passo: Preservação dos registradores.

A primeira instrução em uma função normalmente é assim:

stmdb sp!, {r4 - r6, lr} Ela faz um Push LR, Push R6, Push R5, Push R4.

Esta instrução preserva os valores dos registradores de R4 até R11, e o R13. É total responsabilidade da função preservar esses.

4º Passo:Variáveis Locais

Em seguida, uma operação é realizada na pilha para reservar espaço para as variáveis locais.

sub sp, sp, #0xC

5º Passo: Corpo Então, o corpo da função é executado, em algum momento o compilador decide que o registrador R0 será responsável pelo retorno da função.

6º Passo: Retorno

Se o espaço foi alocado para variáveis locais, ele é então desalocado:

add sp, sp, #0xC

Os registradores salvos no começo são restaurados:

ldmia sp!, {r4 – r6, lr}

pop(r4); pop(r5); pop(r6); pop(lr);

E finalmente o endereço de retorno:

Bx lr

Conjunto de instruções THUMB2

Tradicionalmente todas as instruções da arquitetura ARM tem tamanho regular de 32 bits (4 bytes) Na geração 4 de processadores ARM (Tipo ARM7-TDMI) foi incuido o conjunto de instruções alternativo THUMB em que a maioria das instruções tem 2 bytes. Nos processadores ARM7-TDMI os conjuntos de instruções ARM e THUMB são implementados como dois modos de operação diferentes, necessitando de uma instrução especial para trocar de modo. Na geração 7 (Cortex) foi introduzido o conjunto de instruções THUMB2 com instuções de 2 e 4 bytes que podem acessar todos os recursos do processador. Desta forma podem-se usar instruções de 16 bits ou de 32 bits arbitrariamente sem que seja necessário trocar o modo de operação. Nos processadores Cortex M0, M1, M2 e M3 existem apenas as instruções THUMB2. O suporte ao conjunto ARM é desabilitado.

Na família Cortex o processador de interrupções NVIC foi incorporado ao core do processador, de modo a tornar o uso de interrupções mais simples e mais eficiente que nos chips anteriores da família ARM.

Características da arquitetura ARM-Cortex-M3

Arquivo com 16 registradores de 32 bits, todos com acesso à ULA simultaneamente como 2 operandos e resultado. O segundo operando pode passar por um deslocador tipo Barrel Shifter. Pipeline com 3 estágios: Busca da instrução (Fetch). Decodificação. Execução e armazenamento do resultado. As instruções permitem execução condicional. Instruções de carga e armazenamento de regitradores na memória com endereçamento indexado e auto incremento. Instruções de carga e armazenamento de múltiplos registradores. Multiplicação e divisão em hardware. Arquitetura Harvard: Barramentos separados para busca de instruções e para dados, permitindo acesso simultâneo à memória de dados e de insruções. Espaço de endereçamento unificado: A memória de código, memória de dados, periféricos e bit-band são todos acessíveis no mesmo espaço de endereçamento com endereços de 32 bits. Mapa de memória determinado: As áreas para código, memória interna de dados, periféricos e memória externa tem endereços específicos na definição da arquitetura Cortex. Bit-band: Certas partes da memória são endereçáveis como bits individuais. Interrupções e periféricos integrados

NVIC A arquitetura Cortex-M3 inclui um sofisticado controlador de interrupções chamado NVIC, capaz de controlar interrupções aninhadas com empilhamento automático de contexto. Sys Tick O Sys Tick é um temporizador integrado ao núcleo dos processadores Cortex que serve para gerar interrupções a intervalos regulares de tempo. Bit Band Certas partes da memória são endereçáveis como bits individuais.

Mapa de Memória

O Cortex-M3 é feito para uso em microcontroladores com memória FLASH, SRAM, interfaces GPIO e vários periféricos integrados junto com o Core. Sistemas baseados no Cortex-M3 devem ter um mapa de memória definido:


0xFFFFFFFF-0xE0000000 Periféricos do sistema: NVIC, debug
0x9FFFFFFF0x60000000 Livre para Periféricos Externos
0xDFFFFFFF-0xA0000000 Livre para RAM Externa
0x5FFFFFFF0x40000000 Periféricos definidos pelo fabricante do CHIP
0x3FFFFFFF0x20000000 SRAM (Memória integrada no CHIP)
0x1FFFFFFF0x00000000 Memória FLASH integrada para firmware

First row is a table header Conjunto de instruções

Na arquitetura ARM7 existem dois conjuntos de instruções: Instruções ARM de 32 bits e instruções THUMB de 16 bits. No Cortex M3 existe apenas um conjunto de instruções THUMB2 para todas as operações. O conjunto TRUMB2 usa instruções de 32 e 16 bits, incluindo as instruções THUMB do ARM7 como subconjunto.

O arquivo de registradores

A arquitetura Cortex-M3, assim como o ARM7, tem 16 registradores (R0 a R15) de 32bits com acesso direto à ULA. Algumas instruções THUMB só podem acessar os registradores de R0 a R7. Tres registradores tem propósito especial:

R0 a R7 Registradores do usuário baixos: Todas as instruções tem acesso. R8 a R12 Registradores do usuário altos: Algumas instruções THUMB não tem acesso. R13 ou SP Stack Pointer. Apontador de pilha. Exitstem dois apontadores de pilha, ambos acessíveis como R3: MSP Main Stack Pointer: Este é o apontador de pilha principal, usado no núcleo do sistema operacional e no tratamento de exceções. PSP Process Stack Pointer: Usada em programas aplicativos (modo usuário). As intruções PUSH e POP armazenam ou restauram dados da pilha.

PUSH {R0} ; R13 = R13-4, Memoria[R3] = R0 POP {R0} ; R0 = Memoria[R3], R13 = R13+4; As intruções PUSH e POP usar uma lista de registradores: PUSH {R0, R1, R2, R5} POP {R0-R2, R5} ; Restaura R0, R1, R2 e R5 R14 ou LR Link Register. Conté o endereço de retorno para chamadas de subrotina. A instrução BL <endereço > funciona como uma chamada de subrotina. Ela salva automaticamete o endereço da intrução seuinte no LR e salta para o local indicado pelo operando. Se for necessário aninhar chamadas de subrotina, o LR deve ser salvo na pilha. R15 ou PC Program Counter. Este registrador tem o endereço da próxima instrução que será executada. Registradores Especiais

Fora do banco de registradores R0 a R15 existem alguns registradores que controlam ou indicam aspectos especiais do processador. Eles podem ser classificados em tres grupos:

xPSR, APSR, IPSR, EPSR: Program Status Registers: Tem os bits de estado da ULA: NZCVQ PRIMASK, FAULTMASK e BASEPRI: Prioridade e mascaramento de interrupções CONTROL: Indica o modo de operação: Privilegiado, Usuário ou executando uma excessão Os bits NZCV do xPSR são chamados "Condition Code" abreviado como cc. Em geral eles refletem o resulatdo da última instrução da unidade aritmética.

N Negative: É uma cópia do bit mais significativo do resultado, que indica o sinal. Resultado com bit mais significativo 1 é considerado como negativo.

Z Zero: Indica que deu resultado ZERO na última operação.

C Carry: Bit de transporte na soma ou empréstimo na subtração.

V oVerflow: Indica overflow em uma operação com sinal. Ocorre quando mudou o sinal sem a ativação do carry.

Todas as instruções tem um campo que permite a sua execução condicional de acordo com o estado dos bits NZCV do xPSR. Na linguagem assembly esta execução condicional é indicada por um sufixo de duas letras no mnemonico da instrução de acordo com a tabela a seguir: cc Condição CS C=1 Carry Set EQ Z=1 Equal (zero) VS V=1 Overflow Set GT Greater Then [con sinal] GE Greater or Equal [com sinal] PL N=0 PLus (Positivo) [com sinal] HI HIgher (maior que) [sem sinal] HS Higher or Same [sem sinal] O mesmo que CS cc Condição CC C=0 Carry Clear NE Z=0 Not Equal (não zero) VC V=0 Overflow Clear LT Less Then [com sinal] LE Less or Equal [com sinal] MI N=1 Minus LO Lower (menor que) [sem sunal] LS Lower or Same [sem sinal] A maioria das instruções pode afetar ou não os indicadores de estado no CPSR. Na linguagem assembly coloca-se um sufixo com a letra s no mnemonico da instrução para indicar que os flags devem ser modificados. Por exemplo:

subs R1, R2, R3 /* Calcula R1=R2-R3 e ajusta flags */ addge R4, R4, #1 /* Soma 1 no R4 se o resultado da subs for >= 0 */ AND R5, #7 /* R5 = R5 & 7 Quado tem 2 operandos o destino=primeiro op */ As instruções de processamento de dados geralmente tem 3 argumentos:

op1: O primeiro argumento é um registrador onde o resultado é armazenado op2: O segundo argumento é um registrador usado como primeiro operando da operação op3: O terceiro argumento é o segundo operando da operação, que pode ser um valor imediato de 8 bits, um registrador ou um registrador com deslocamento. As instruções de 3 argumentos são as seguintes: instruções de 3 argumentos AND op1,op2,op3 op1 = op2 & op3 E bit a bit EOR op1,op2,op3 op1 = op2 ^ op3 Ou exclusivo ADD op1,op2,op3 op1 = op2 + op3 Soma SUB op1,op2,op3 op1 = op2 - op3 Subtração RSB op1,op2,op3 op1 = op3 - op2 Subtração reversa ADC op1,op2,op3 op1 = op2 + op3 Soma com carry SBC op1,op2,op3 op1 = op2 - op3 Subtração com carry RSC op1,op2,op3 op1 = op3 - op2 Subtração reversa com carry ORR op1,op2,op3 op1 = op2 | op3 Ou bit a bit BIC op1,op2,op3 op1 = op2 & ~op3 Bit clear (zera bits) Nas instruções com 2 operandos o primeiro deve ser um registrador e o segundo pode ser um valor imediato de 8 bits, um registrador ou um registrador com deslocamento.

Exemplos de intruções de 3 operandos:

ORR R1, R2, #0x20 @ R1 = R2 | 0x20 ADD R2, R3, R4, LSL #3 @ R2 = R3 + (R4 << 3) RSB R4, R5, #0 @ R5 = 0 - R5 SUB R1, R2, R3, LSR R4 @ R1 = R2 - (R3 >> R4) instruções de 2 argumentos MOV op1, op2 op1 = op2 Copia op2 em op1 MVN op1, op2 op1 = ~op2 Copia op2 negado em op1 CMP op1, op2 op1 - op2 Compara: Subtrai ajustando CPSR sem armazenar o resultado CMN op1, op2 op1 - ~op2 Compara com o segundo operando negado TST op1, op2 op1 & op2 Testa bits: Faz E ajustando CPSR sem armazenar o resultado TEQ op1, op2 op1 ^ op2 Testa bits: Faz XOR ajustando CPSR sem armazenar o resultado Instruções de leitura da memória.

Nesta listagem Rd e Re podem ser registradores R0 a R15. Rd é o registrador que recebe o valor lido da memória; Re é o reg que contém o endereço de memória que será lido. offset é uma constante positiva ou negaiva de 12 bits usada para modificar o endereço. Instruções de leitura da Memória para Registrador LDR Rd,[Re, #offset] Rd := memória[Re + offset]; Le 32 bits LDRH Rd,[Re, #offset] Rd := memória[Re + offset]; Le 16 bits (Half word) LDRB Rd,[Re, #offset] Rd := memória[Re + offset]; Le 8 bits (Byte) LDR Rd,[Re, #offset]! Rd := memória[Re + offset]; Re := Re + offset; Le 32 bits e modifica Re LDR Rd,[Re, Ri] Rd := memória[Re + Ri] Le memória com endereço formdo pela soma de 2 registradores LDR Rd,[Re], #offset Rd := memória[Re]; Re := Re + offset; Le 32 bits e modifica Re com pós incremento Instruções de escrita na memória.

Nesta listagem Rf e Re podem ser registradores R0 a R15. Rf é o registrador que será armazenado na memória; Re é o reg que contém o endereço na memória. offset é uma constante positiva ou negaiva de 12 bits usada para modificar o endereço. Instruções escrita de Registrador na Memória STR Rf,[Re, #offset] memória[Re + offset]:= Rf; Escreve 32 bits STRH Rf,[Re, #offset] memória[Re + offset]:= Rf; Escreve 16 bits (Half word) STRB Rf,[Re, #offset] memória[Re + offset]:= Rf; Escreve 8 bits (Byte) STR Rf,[Re, #offset]! memória[Re + offset]:= Rf; Re := Re + offset; Le 32 bits e modifica Re STR Rd,[Re], #offset memória[Re]:= Rf; Re := Re + offset; Escreve 32 bits e modifica Re com pós incremento Instruções de salto

Salto relativo ao PC:

B enderco_destino @ Salto incondicional BEQ iguais @ Salta se Z=1 (Iguais) BCS carry_set Chamada de subrotina:

BL subrotina1 A instrução BL salva o endereço de retorno no R14 (que é o LR Link-Rgister) e salta para a subrotina. Para reornar, da subrotina pode-se copiar o LR no PC com subrotina1: @ Operações da subrotina MOV PC,LR @ Retorna da subrotina O método acima não é aninhável. Não se poderia chamar outra subrotina de dentro desta subrotina porque o valor do LR seria alterado. Subrotinas que chamam subrotinas, devem salvar o LR na pilha: subrotina2: PUSH {R1, R2, LR} @ Salva na pilha R1, R2, LR @ Operações da subrotina POP {R1, R2, PC} @ Restaura R1 e R2 e retorna da subrotina