Capítulo 3 Processadores de Propósito Geral: Softwareattux/cap3_09_05.pdf · Processadores de...

Preview:

Citation preview

Capítulo 3 – Processadores

de Propósito Geral: Software

Prof. Romis Attux

EA075 – 2015

Obs: Os slides são parcialmente baseados nos dos autores do livro texto e do Prof. Levy Boccato

Processadores de Propósito

Geral Um processador de propósito geral

(PPG) é um sistema “universal”, ou seja, um sistema computacional capaz de resolver uma ampla gama de tarefas.

Há vantagens e desvantagens de se usar um PPG. Falemos das vantagens.

O custo por unidade pode ser baixo, o desempenho pode ser muito bom, e tamanho e consumo podem até mesmo ser razoáveis.

Processadores de Propósito

Geral O custo NRE do projetista do sistema

embarcado tende a ser pequeno, pois o foco do projeto estará no software. Isso também tende a gerar um baixo tempo de prototipagem e um baixo TTM, além de gerar alta flexibilidade devida à operação no nível do software.

Arquitetura Básica

Três elementos centrais: Datapath, unidade de controle e memória.

Datapath (Caminho de Dados)

O caminho de dados realiza tarefas de processamento e dispõe de funcionalidades para armazenamento temporário da informação (registradores).

O coração do processamento é a ULA (unidade lógica e aritmética), que realiza várias operações matemáticas e lógicas e armazena diversos sinais de status pertinentes (zero, carry, overflow etc.).

Datapath (Caminho de Dados)

Dados temporários armazenados em registradores

podem incluir:

◦ Dados trazidos da memória e não processados.

◦ Dados gerados pela ULA que ainda serão necessários

para processamento posterior.

◦ Dados que serão mandados de volta para a memória.

◦ Dados que podem ser movidos de uma posição de

memória para outra

Um barramento interno transporta os dados no

datapath enquanto outro barramento faz a

comunicação com a memória.

Datapath (Caminho de Dados)

É usual falar no “tamanho de um processador”, e a largura do barramento do caminho de dados é a métrica crucial aqui.

Um processador de N bits pode ter registradores de N bits, uma ULA operando com N bits etc. Tamanhos comuns (ou clássicos) são 8, 16, 32 e 64 bits.

Datapath (Caminho de dados)

Unidade de Controle (UC)

Se o caminho de dados é uma orquestra que executa uma partitura (programa armazenado), a unidade de controle é um maestro obcecado que dá todas as deixas para seus músicos.

Basicamente, a UC possui funcionalidades de busca e decodificação de instruções e gera sinais capazes de manipular o caminho de dados para realizar essas instruções.

Unidade de Controle (UC)

Falaremos de dois registradores que a UC possui:

◦ PC (Program Counter): registrador que contém o endereço

da próxima instrução a ser buscada na memória.

◦ IR (Instruction Register): registrador que guarda a

instrução buscada na memória.

A unidade também possui circuitaria sequencial para

gerar sinais de controle para o caminho de dados.

A frequência de relógio dá uma idéia da velocidade do

processador, pois ela influencia o ritmo da pulsação

básica fetch-decode-execute.

Unidade de Controle (UC)

A UC também determina o próximo valor do PC. Se as instruções não envolvem saltos (jumps ou branches), a operação corresponde a um incremento.

Para uma instrução de branch, é usual que se analisem “flags” gerados pela ULA para determinação do próximo endereço.

O tamanho do PC determina o tamanho do espaço de endereçamento do processador.

Se o PC contém M bits, ele pode apontar para 2M endereços distintos de memória.

Unidade de Controle (UC)

A unidade de controle, tipicamente, pulsa num ritmo de busca de instrução, decodificação, busca de operandos, execução pelo caminho de dados e armazenamento dos resultados.

Cada estágio pode demandar um ou mais ciclos de clock.

O caminho pelo datapath que resulta no maior tempo de execução é chamado de caminho crítico.

Unidade de Controle (UC)

Memória

A memória de um computador, via de regra, armazena informação utilizada a médio e longo prazos.

Essa informação pode ser parte de um programa ou de um conjunto de dados.

Quando dados e programa ocupam o mesmo espaço de memória, fala-se em arquitetura Princeton.

Quando há uma separação, fala-se em arquitetura Harvard.

Memória - Tipos

Tipos Básicos de Memória

Memória ROM (Read-Only Memory): memória que pode apenas ser lida (embora algumas variedades mais modernas, como EPROMs, possam sofrer escrita).

Memória RAM (Random-Acess Memory): memória que pode ser agilmente lida e escrita.

Um sistema embarcado, por vezes, usa uma memória ROM para gravar o programa (função única).

Memória

On-chip: no mesmo chip do processador.

Off-chip: externa ao processador. A primeira é acessada mais

rapidamente, mas, por outro lado, ocupa espaço junto ao CI.

Hierarquia de Memória e

Memória Cache Veremos mais detalhadamente o conceito de

hierarquia de memória, mas, por ora, podemos pensar numa mescla de diferentes tipos de memória (com capacidades e velocidades de acesso distintas) que se interconectam de modo a explorar localidades temporais e espaciais presentes nos códigos computacionais.

No caso, falaremos rapidamente de memória cache e de sua relação com a chamada memória principal do computador.

Memória Cache

A memória cache é uma memória de dimensão

reduzida (em relação) à memória principal, mas que

possui maior velocidade.

Normalmente se encontra no chip e é uma RAM

estática “rápida”, em contraste com a RAM dinâmica da

memória principal.

A idéia é que a localidade espaço-temporal presente

nos códigos permita aproveitar bastante a informação

contida na cache (cache hits) antes que seja preciso

buscar informação nova (cache miss) na memória

principal (mais lenta).

Memória Cache

Execução de Instruções

Pode-se pensar, de maneira geral e simples, na execução de instruções em termos de cinco passos fundamentais: ◦ Busca da Instrução (Fetch Instruction)

◦ Decodificação da Instrução

◦ Busca dos Operandos (Fetch Operands)

◦ Execução

◦ Armazenamento dos Resultados

Pipelines

A execução de instruções pode ser significantemente acelerada através do uso de pipelines na execução das instruções.

Basicamente, pipelines são “linhas de produção” de execução de instruções, que exploram o paralelismo intrínseco à execução de uma sequência de instruções.

Um exemplo simples nos ajudará a compreender isso.

Pipelines

Pipelines

Se pensarmos nos cinco estágios descritos, poderíamos ter, por exemplo, a busca por uma instrução sendo feita enquanto se decodifica uma instrução anterior.

O desempenho de pipelines cheios numa operação sequencial é excepcional, pois cada ciclo significa a execução de uma instrução.

Porém, a existência de branches significa uma dificuldade, pois esse tipo de instrução pode gerar desvios no fluxo de execução.

Execução com Pipeline (Caso

Ideal)

Pipelines

Uma possibilidade é simplesmente parar o pipeline quando há um branch até que o endereço de execução se resolva. Isso causa bolhas no pipeline.

Outra possibilidade é usar algoritmos de previsão de branches para tentar evitar, ao menos em certos casos, bolhas. Um erro de predição, naturalmente, levaria à penalidade de remontar todo o fluxo do pipeline.

Bolha num Pipeline Causada

por Erro no Tratamento de um

Branch (6 Estágios)

Outros Problemas • Quando diferentes estágios precisariam do

mesmo recurso ao mesmo tempo, podem também surgir bolhas.

• No exemplo a seguir, o pipeline busca um operando na memória no mesmo instante em que deveria buscar uma instrução na memória causando um atraso de um ciclo de operação.

Bolha Estrutural

Outros Problemas

Podem surgir bolhas também pela necessidade de acessar um mesmo dado por instruções distintas.

Considere o caso a seguir: ◦ A A + B

◦ C C - A

A segunda instrução precisará do valor de A, mas ela não o terá até que a primeira se conclua.

O que ocorre está na figura a seguir.

Bolha – Dados em Comum

Visão do Programador • O programador escreve as instruções que

fazem com que o processador de propósito geral realize as tarefas desejadas. Ele pode ter uma visão mais ou menos detalhada da arquitetura subjacente, mas um mínimo é sempre necessário.

• A programação em alto nível, feita usualmente por meio de linguagens estruturadas, leva a programas com instruções genéricas e muito próximas de um algoritmo.

Visão do Programador

Por outro lado, quando se programa em Assembly, utiliza-se diretamente o conjunto de instruções do processador. Com isso, o programador obrigatoriamente tem de ter uma visão clara da arquitetura.

A tradução de linguagens de alto nível para as linguagens assembly é feita por programas conhecidos como compiladores, que são essenciais para que a máquina possa efetivamente “dar vida” ao código.

Visão do Programador

Ainda existe um nível mais baixo, o do código de máquina, no qual as instruções são codificadas diretamente como zeros e uns. O uso de assemblers serve exatamente para evitar essa necessidade quando se deseja programar em baixo nível.

Conjunto de Instruções

Quando programa em assembly, é preciso conhecer o conjunto de instruções da máquina (lembrem-se das experiências com o ARM!).

Uma instrução tem tipicamente duas

partes – um código de operação (opcode) e campos relativos a operandos.

Tipos de Instruções

Transferência de dados: servem para mover dados entre a memória e registradores, entre canais de entrada saída e registradores e entre registradores.

Instruções lógico-aritméticas: configuram a ULA para realizar determinadas funções, ou mover resultados para determinados registradores.

Branches podem ser pulos incondicionais, pulos condicionais ou chamadas / retornos de procedimentos.

Operandos

Um campo de operando pode indicar dados que farão parte da operação (fonte) ou um local para armazenagem de resultados (destino).

O número de operandos especificados por instrução varia de processador para processador e pode variar entre as próprias instruções.

Um campo de operando por usar vários modos de endereçamento.

Modos de Endereçamento

Conjunto de Instruções Simples

Programas – C e Assembly

Vejamos um programa numa linguagem de alto nível e seu equivalente assembly.

Cuidados

Avaliar o espaço disponível para dados e programa.

Conhecer os registradores da arquitetura e suas funções específicas quando for o caso.

Conhecer a forma de lidar com entrada e saída provida pelo processador.

Interrupções

Quando ocorre uma interrupção, o processador para o fluxo normal de execução e pula para uma rotina de serviço (que é projetada para tratar aquilo que causou a interrupção).

O processador precisa salvar o PC e colocar nele o endereço da rotina de serviço. Ele também precisa salvar outros elementos do contexto (e.g. o conteúdo de certos registradores).

Interrupções

Quando volta da rotina de serviço, o processador restaura o

conteúdo original do PC e, eventualmente, de outros

elementos, e segue o fluxo de execução.

Cada rotina precisa estar numa região distinta da memória, e

o programador deve estar atento a isso.

Um exemplo seria o tratamento de um evento associado a

um periférico (e.g. um botão). Pode-se utilizar uma posição

de memória para registrar esse evento e verificá-la

periodicamente, mas seria mais interessante escrever uma

rotina de serviço e associá-la ao pino conectado ao botão.

Apertado o botão, gera-se a interrupção e chama-se a rotina.

Sistema Operacional

Um sistema operacional é uma camada de software que provê serviços de baixo nível para a camada de aplicação, um conjunto de um ou mais programas executando na CPU consumindo e produzindo dados.

As tarefas do sistema envolvem carregar e executar os programas, compartilhar e alocar recursos do sistema para esses programas e proteger esses recursos contra corrupção.

Sistema Operacional

Um dos recursos mais importantes é a CPU que é

compartilhada por vários programas em execução. O

sistema decide qual programa é executado na CPU e

por quanto tempo, e usa o conceito de processo para

isso.

O gerenciamento de processos é uma tarefa crucial

que será estudada em detalhes em outros cursos.

Outro recurso importante gerenciado pelo sistema é a

memória, incluindo aí o conteúdo armazenado em

disco. Falaremos disso mais adiante.

Sistema Operacional

Além disso, o sistema provê software necessário para lidar com várias

interrupções de hardware, e drivers para comandar periféricos.

Um conceito importante é o de chamada de sistema (system call), um mecanismo

pelo qual uma aplicação invoca o sistema (o que lembra a chamada de uma

função numa linguagem de alto nível).

Um programa pode gerar uma chamada desse tipo quando precisa de algum

serviço provido pelo sistema.

Em suma, o sistema operacional “esconde” do usuário uma série de aspectos de

baixo nível, favorecendo um uso “simples”. As chamadas de sistema fazem uma

ponte entre a camada de aplicação e as camadas de mais baixo nível.

Ambiente de Desenvolvimento

Ambiente de Desenvolvimento

Há similaridades, mas também diferenças importantes

entre a forma de criar um programa em um desktop e

num sistema embarcado. Num desktop, poderíamos ter

um esquema como a seguir.

Ambiente de Desenvolvimento

Num sistema embarcado, tipicamente o processador usado é

diferente daquele em que ocorreu o desenvolvimento. Deve haver

compatibilidade.

Há várias ferramentas importantes:

◦ Compiladores: traduzem programas de alto nível em linguagem assembly (ou

mesmo de máquina). Compiladores cruzados são muito importantes, pois

permitem que uma máquina gere código para outra.

◦ Assemblers (Montadores): traduzem instruções assembly em instruções de

máquina.

◦ Linkers: permite que o programador crie programas em diferentes arquivos

compilados ou montados.

Teste de Software

Uma parte importante do desenvolvimento de software é a fase de teste, na qual o código desenvolvido deve ser avaliado em diversas condições e com diversas entradas.

É uma fase difícil mas crucial, pois um erro sério pode inviabilizar a operação do sistema embarcado.

Teste de Software

Para o caso de sistemas embarcados, há desafios adicionais: ◦ Se a aplicação for de tempo real, é

preciso levar em conta o fator tempo no teste.

◦ O sistema embarcado interage com o ambiente, o que traz novas variáveis que devem ser levadas em conta no teste.

Debuggers

Debuggers são ferramentas que auxiliam o projetista a avaliar e corrigir seus programas.

Eles permitem a execução passo-a-passo, a inserção de breakpoints etc.

Como rodam na máquina de desenvolvimento, eles podemos ser chamados de simuladores de conjunto de instruções ou máquinas virtuais.

Emuladores

Emuladores basicamente dão suporte ao processo de debugging enquanto o programa roda no processador alvo.

Basicamente, os emuladores são dispositivos específicos conectados ao processador alvo, através de uma placa, por meio de um cabo. A placa contém o processador alvo e circuitaria de suporte. Pode ainda haver outro cabo ligado a um dispositivo com a mesma configuração de pinos do processador alvo, o que permite a colocação em um sistema embarcado real (o que pode ser caro).

Device Programmers

Os device programmers carregam, a partir da máquina de desenvolvimento, um programa em linguagem de máquina desenvolvido pelo processador de trabalho no processador alvo para que ele possa ser testado em campo, por exemplo.

Modalidades de Teste

Se usarmos um processo de debugging com simulador,

teremos velocidade e facilidade, mas é limitado em

termos de interação com o ambiente.

Se usarmos um emulador, teremos um ciclo mais

longo, pois teremos de carregar código no emulador,

mas ele pode interagir com o restante do sistema.

Por fim, o ciclo usando o programador requer que o

processador seja retirado do sistema, programado, e

recolocado, o que gera uma demora expressiva, mas é

um caso realista (embora com pouco controle de

debug).

ASIPs

Falaremos agora brevemente de ASIPs, que são

programáveis como processadores de propósito geral,

mas possuem certas funcionalidades próprias.

Microcontroladores são ASIPs que incluem,

tipicamente:

◦ Dispositivos de conversão analógico-digital, timers e

dispositivos de comunicação serial no chip.

◦ Podem prover acesso direto por parte do programador a

certos pinos.

◦ Provêem algumas operações típicas de controle

embarcado, como operações de manipulação de bit.

ASIPs

Digital Signal Processors (DSPs) são altamente otimizados para operações usadas no tratamento de sinais de informação.

Isso pode significar um poder expressivo de computação numérica (registradores e ULAs, por exemplo), e a incorporação de funções típicas de filtragem e análise espectral.

Também são incorporadas funcionalidades de conversão analógico-digital, timers, contadores etc.

Projeto de um Processador de

Propósito Geral De certa forma, um processador de

propósito geral lembra um processador específico que processa instruções, com um caminho de dados de grande generalidade, armazenadas na memória.

Faremos um projeto didático a seguir que ilustra isso. Recordemos, para tanto, a arquitetura de um processador de propósito geral.

Projeto de um Processador de

Propósito Geral

Projeto da Unidade de Controle

Comecemos criando a unidade de controle. Ela utilizará o PC (16 bits), o IR (16 bits), uma memória de 64k x 16 bits, e um arquivo de registradores 16 x 16 bits.

O estado inicial, Reset, faz com que o PC seja zero.

O estado Fetch lê M[PC] em IR. O estado Decode gera um ciclo para que o IR seja atualizado e se tenha acesso às informações necessárias.

Projeto da Unidade de Controle

De posse da informação do IR, fazem-se múltiplos arcos, que representam as diferentes instruções expressas pelo repertório de opcodes.

Considerar-se-ão instruções Mov1 (memória registrador), Mov2 (registrador memória), Mov3 (registrador memória / indireto), Mov 4 (valor registrador), Add (soma entre o conteúdo de registradores), Sub (subtração entre o conteúdo de registradores), Jump (atualiza o PC com um valor de endereço usando a ULA).

Ilustração da Unidade

Caminho de Dados

A criação do caminho de dados vai pressupor que a ULA é capaz de realizar todas as operações pertinentes. Também pressuporá as funcionalidades necessárias para o arquivo de registradores.

Caminho de Dados

Caminho de Dados

(Conferir)

Diferenças Fundamentais

Um processador de propósito único “cristaliza” um programa em sua unidade de controle, enquanto um processador de propósito geral possui a flexibilidade de um programa armazenado.

O caminho de dados de um processador de propósito único é customizado para a aplicação, enquanto o caminho de dados de um processador de propósito geral deve ser flexível.

Recommended