• No results found

2. Teoridel

2.1. Familievold

Uma técnica em hardware que utiliza dispositivos reconfiguráveis consiste em uma tradução binária, que possui a característica de armazenar as traduções para reuso futuro, e pode ser implementado como uma camada de software ou hardware. O método de tradução binária consiste em converter um código já compilado para um determinado conjunto de instruções apontado pelo processador, no qual o código será realmente executado. Esta tradução permite executar um aplicativo dependente de um hardware proprietário em outro sistema que utiliza um conjunto de instruções diferente. Para o usuário do sistema, esta tradução é abstraída e o aplicativo é executado da mesma forma como se o programa estivesse sendo utilizado no processador nativo.

Um tradutor binário pode ser classificado em três tipos diferentes, segundo [Altman, Kaeli e Sheffer, 2000]: emulador, Tradutor Estático e Tradutor Dinâmico. O emulador realiza a interpretação do código em tempo de execução, baseada em acessos a tabelas que contêm as possíveis configurações da arquitetura para qual a instrução será traduzida. Sua tradução não é salva em memória para reutilização futura. O Tradutor Estático realiza a tradução em tempo de compilação, sendo possível utilizar informações extraídas em tempo de execução do aplicativo. Já o Tradutor Dinâmico realiza a tradução do código em tempo de execução (run-time), com a possibilidade de armazenar em memória partes do código para uso futuro, dispensando um conhecimento profundo da arquitetura pelo programador ou usuário.

O trabalho de [Fajardo Jr, 2011] propõe um sistema dinâmico de tradução binária de dois níveis, que executa um código compilado para o conjunto de instruções x86 em uma arquitetura reconfigurável, onde este sistema será capaz de executar o conjunto de instruções MIPS.

O primeiro nível deste tradutor binário é responsável por traduzir o código nativo para um código genérico, da mesma forma que um tradutor binário convencional. Para tanto, foi desenvolvido um novo mecanismo dinâmico implementado em hardware que funciona como interface entre o processador e a memória de instruções. O segundo

34 nível de tradução é responsável por otimizar ou acelerar sequências de instruções deste código comum já traduzidas para a arquitetura alvo. Este código é, por sua vez, traduzido para ser executado em uma arquitetura reconfigurável, a qual é composta por um processador MIPS fortemente acoplado com um segundo nível de tradução binária e uma unidade reconfigurável fortemente acoplada de granularidade grossa [BECK et al., 2008]. Os trechos traduzidos são chamados agora de “configurações”, e são alocados na TCache para serem executados novamente de acordo com o fluxo do programa, porém agora na unidade de reconfigurável. A Figura 3.1 ilustra uma visão geral de sua proposta.

Figura 4.1 – Mecanismo de tradução binária em dois níve

Fonte: [Fajardo Jr, 2011]

Ainda segundo [Fajardo Jr, 2011], o funcionamento deste mecanismo ocorre da seguinte forma: o primeiro nível do tradutor busca as instruções CISC na memória, como um processador comum. As instruções são traduzidas gerando uma ou mais

35 instruções MIPS equivalentes. A cada envio de uma instrução traduzida para o processador, o tradutor calcula o novo endereço da memória de instruções.

O componente de hardware do primeiro nível do tradutor binário é composto por quatro diferentes unidades: Tradução, Montagem, PC (Program Counter) e uma unidade de Controle, formando dois estágios de pipeline, para que seja possível a tradução e o cálculo do novo endereço ao mesmo tempo. Na Figura 3.2 é proposta uma visão geral do mecanismo de tradução.

Figura 4.2 – Unidades do mecanismo de tradução binária

Fonte: [Fajardo Jr, 2011]

A Unidade de Tradução é responsável por buscar as instruções x86 da memória (uma instrução por vez), analisar o seu formato, quantidade de bytes que a compõe e classificá-la de acordo com a operação, operadores e modo de endereçamento, gerando então instruções equivalentes MIPS. Nesta unidade é realizado principalmente operações de acesso a tabelas. Além de realizar a tradução, esta unidade deve fornecer informações para as unidades auxiliares como: a quantidade total de bytes no qual a instrução x86 é formada (importante para o cálculo do endereço da próxima instrução), o número de instruções MIPS geradas para verificar a disponibilidade na fila de instruções da unidade de montagem, e ainda informar o tipo de instrução (operação

36 lógica, saltos condicionais ou incondicionais, flags de estado que poderão ser modificadas pela instrução, etc).

Esta unidade possui 4 diferentes tabelas e um hardware especial para manipular valores imediatos. Em cada uma destas tabelas e hardware de imediatos, as saídas são bits de configuração para serem enviadas ao componente de hardware responsável por descartar bits de configuração que não serão utilizados e os colocar em ordem correta. Neste instante são conhecidos a operação da instrução e os operadores que compõem determinada instrução x86. Na sequência, os bits de configuração são enviados para a unidade que decodifica esta informação e a partir dela monta a instrução no formado do conjunto MIPS. As instruções MIPS são geradas dependendo da sua operação: nos formatos R, I ou J.

O processador MIPS utilizado busca novas instruções vindas do tradutor binário de forma sequencial, da mesma forma que o processador original busca suas instruções de uma memória regular. A Unidade de Montagem disponibiliza as instruções equivalentes MIPS de forma sequencial como se fosse uma memória comum, e é formada por um banco de registradores de 32 bits, nos quais as instruções provenientes da Unidade de Tradução são alocadas. A cada ciclo é enviado para a Unidade de Controle a quantidade de instruções que estão ocupando os registradores, de forma a garantir que não existirá descontinuidade no processo de fornecimento de instruções MIPS para o processador, reduzindo eventuais bolhas ou paradas na execução do código que possam surgir.

A instruções x86 possuem tamanhos variáveis, impossibilitado o reaproveitamento do hardware do processador MIPS para o cálculo do próximo endereço na busca de novas instruções. Desta forma, foi implementada uma Unidade de PC, que calcula o próximo endereço da nova instrução a ser buscada na memória, baseando-se na quantidade de bytes em que é composta a instrução x86 corrente, e somando esse número ao endereço atual, ou calculando o endereço através de um valor imediato contido em uma instrução de salto incondicional.

A Unidade de Controle permite que seja mantida a sincronia e a consistência da informação entre as unidades de Tradução, Montagem e de PC. A unidade de controle pode repassar informações como o momento em que a Unidade de Tradução pode buscar uma nova instrução na memória ou como deve ser calculado o endereço de PC. Esta unidade é baseada em uma máquina de estados finitos.

37 A segunda etapa da tradução contém uma arquitetura reconfigurável denominada DIM (Dynamic Instruction Merge), desenvolvida por [Beck e Carro, 2005] [Beck et al., 2008]. A arquitetura DIM é composta por um sistema de tradução binária, uma TCache onde são alocadas as configurações geradas pelo tradutor e uma unidade reconfigurável responsável pela execução das configurações.

A unidade reconfigurável é formada por uma matriz dinâmica de grão grosso fortemente acoplada ao processador, o que propicia que a reconfiguração ocorra em unidades funcionais completas. Na fase de execução do código, a unidade reconfigurável funciona como uma extensão do estágio de execução do processador, atuando de forma totalmente independente e sem a necessidade de acesso externo.

A matriz de unidades funcionais possui duas dimensões, onde cada instrução é alocada na interseção entre uma linha e uma coluna. As unidades funcionais alocadas lado a lado podem executar operações em paralelo, já as unidades alocadas na mesma coluna se caracterizam por executar as operações de forma combinacional, uma após a outra. Desta forma, se duas instruções não possuem nenhum tipo de dependência de dados entre si, existe a possibilidade de serem alocadas na mesma linha, ou seja, com execução paralela. Caso contrário, serão obrigatoriamente alocadas em linhas diferentes. Cada coluna possui um número pré-determinado de unidades funcionais, podendo ser ULAs, multiplicadores, unidades de load/store, entre outras. Dependendo do tempo de execução de cada unidade funcional, o processador pode executar mais de uma operação por ciclo de relógio.

No exemplo da Figura 4.3, o primeiro grupo de unidades funcionais suporta a execução de até 4 operações em paralelo por meio de suas ULAs, o segundo grupo suporta duas unidades de leitura/escrita (load/store) em paralelo e o terceiro grupo oferece uma unidade multiplicadora dedicada.

38

Figura 4.3 – Configuração de uma unidade reconfigurável da arquitetura DIM

Fonte: [BECK. e CARRO, 2005]

O processo de reconfiguração ocorre da seguinte forma: os valores contidos em um banco de registradores são enviados por um barramento de operadores, de modo que cada linha do barramento é conectada a todas as unidades funcionais por meio de multiplexadores – Fig. 4.3(a). Na sequencia de cada unidade funcional é acoplado um multiplexador de saída – Fig. 4.3(b), que seleciona em qual linha do barramento será destinado o resultado da operação. A partir do quadro da Fig. 4.3(c), a primeira instrução é alocada na primeira unidade lógica (visualizada de baixo para cima), armazenando o resultado da adição.

A Figura mostra a sequência de armazenamento de dados das instruções nas linhas e colunas das unidades lógicas de acordo com a dependência verdadeira de dados entre as instruções, definindo a ordem de execução em série ou em paralelo. As instruções 6 e 7 possuem dependência com as instruções 1, 2 e 3, devendo ser executadas no próximo ciclo de relógio e alocadas nas unidades de load/store correspondentes. Já a instrução 8 possui dependência direta com a instrução 7, o que também impossibilita o uso da unidade multiplicadora no mesmo ciclo, ocasionando um terceiro ciclo de relógio.

Os blocos básicos desta unidade são sequências de código situadas entre desvios ou chamadas de função. A execução do tradutor se inicia após uma instrução de desvio e finaliza ao encontra outra instrução não suportada ou uma nova instrução de desvio. A implementação do tradutor possui 4 estágios: decodificação, análise de dependências, atualização de tabelas e montagem de configuração. A instrução é decodificada no

39 primeiro estágio, fornecendo para o segundo estágio informações como tipo de operação e operadores. O segundo estágio verifica as dependências para manter a coerência dos dados durante a execução. O terceiro estágio atualiza as tabelas de configurações e o último estágio organiza as tabelas e monta uma nova configuração quando houver uma quebra de configuração ocasionada por uma instrução de desvio ou não suportada.

Um conjunto de tabelas é utilizado para manter as informações sobre a sequência de instruções processadas, responsáveis por armazenar dados como configuração dos multiplexadores, operação das ULAs, mapa binário da alocação de cada instrução na matriz, tabela de dados a serem buscados no banco de registradores, entre outros. O processo de tradução ocorre de forma paralela ao processador.

Ao finalizar o processo de tradução, é montada uma configuração indexada ao endereço da primeira instrução da sequência do código traduzido, armazenada na TCache para um futuro reuso. Caso uma mesma sequência de código for encontrada pela segunda vez, será encontrada na TCache a configuração com o mesmo endereço e com o código já traduzido e otimizado. Desta forma, ocorre uma execução direta do código na unidade reconfigurável, dispensado o uso do processador MIPS e da tradução binária.