UNIVERSIDADE FEDERAL DE SANTA CATARINA PROGRAMA DE PÓS-GRADUAÇÃO EM CIÊNCIA DA COMPUTAÇÃO Leonardo Taglietti GERAÇÃO AUTOMÁTICA DE FERRAMENTAS DE SUPORTE AO DESENVOLVIMENTO DE SOFTWARE EMBARCADO PARA ASIPs Dissertação submetida à Universidade Federal de Santa Catarina, como parte dos requisitos para obtenção do grau de Mestre em Ciência da Computação. Prof. Olinto José Varela Furtado, Dr. Orientador Prof. Luiz Cláudio Villar dos Santos, Dr. Co-orientador Florianópolis, fevereiro de 2005. GERAÇÃO AUTOMÁTICA DE FERRAMENTAS DE SUPORTE AO DESENVOLVIMENTO DE SOFTWARE EMBARCADO PARA ASIPs Leonardo Taglietti Esta Dissertação foi julgada adequada para a obtenção do tı́tulo de Mestre em Ciência da Computação (Sistemas de Computação) e aprovada em sua forma final pelo Programa de Pós-Graduação em Ciência da Computação. Prof. Raul Sidnei Wazlawick, Dr. (coordenador) Banca Examinadora Prof. Olinto José Varela Furtado, Dr. (orientador) Prof. Luiz Cláudio Villar dos Santos, Dr. (co-orientador) Prof. Guido Costa Souza de Araújo, Dr. Prof. Luiz Fernando Friedrich, Dr. “Se em horas de encontros pode haver tantos desencontros, que a hora da separação seja, tão somente, a hora de um verdadeiro, profundo e coletivo encontro. De tudo ficarão três coisas: a certeza de estar sempre começando, a certeza de que é preciso continuar e a certeza de ser interrompido antes de terminar. Fazer da queda um passo de dança, do medo uma escada, do sonho uma ponte, da procura um encontro.” Fernando Sabino Recebi este manuscrito da Ionara, minutos antes de partir rumo ao mestrado. Valeu, mana! Aos meus pais, Celso e Lidia... Agradecimentos Neste momento, desejo compartilhar minha alegria em concluir este curso de mestrado, exteriorizando minha gratidão: Aos meus pais, Celso e Lidia, ao Eliseu, Jans, Ionara e Sabrina, pelo incentivo que nunca termina e sempre me fortalece. À minha namorada Jeane, pelo amor e presença, principalmente nos últimos meses. Aos professores Olinto e Luiz Claúdio, pelo exemplo profissional e pela oportunidade de trabalho. A partir das suas valiosas orientações, pude concretizar mais esta etapa da minha vida. Aos colegas de laboratório, pelas longas jornadas de trabalho vencidas. Em especial, ao José Otávio, Daniel e Gabriel, pela direta participação neste trabalho. Aos membros do Laboratório de Sistemas de Computação da UNICAMP, pela atenção concedida. À Vera Lúcia (Verinha), secretária da pós-graduação, pela amizade e companhia. Ao amigo e professor Luiz Carlos Zancanella, pela amizade e incentivo constante. Aos amigos Gilmar e Magália Benini, Geomar Martins, Roberto Leão e Alexandre Zanatta, que de alguma forma contribuı́ram antes ou durante estes anos. Aos professores Nelson Zang e Eduardo Appel da URI/FW, que motivaram meu ingresso no curso de mestrado. À Universidade Federal de Santa Catarina, pela estrutura fı́sica disponibilizada. Ao Conselho Nacional de Desenvolvimento Cientı́fico e Tecnológico do Brasil (CNPq), no âmbito do Programa Nacional de Microeletrônica, pelo auxı́lio financeiro concedido (Bolsa 132930/2003-0). E a Deus, fundamento da minha fé, pela constante presença. Leonardo Taglietti Sumário Lista de figuras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 Lista de tabelas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 Lista de siglas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 Abstract . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 1 Introdução 16 1.1 Alternativas de implementação . . . . . . . . . . . . . . . . . . . . . . . . . 16 1.2 Requisitos de um sistema embarcado . . . . . . . . . . . . . . . . . . . . . 18 1.3 Fluxo de projeto e nı́veis de descrição . . . . . . . . . . . . . . . . . . . . . 19 1.4 Contexto desta dissertação . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 1.5 Foco e contribuições da dissertação . . . . . . . . . . . . . . . . . . . . . . 21 1.6 Organização da dissertação . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 2 Trabalhos correlatos 2.1 2.2 23 Um panorama das ADLs . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 2.1.1 nML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 2.1.2 LISA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 2.1.3 EXPRESSION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 2.1.4 ISDL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 2.1.5 ArchC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 Abordagens para a geração de ferramentas . . . . . . . . . . . . . . . . . . 27 2.2.1 Ferramentas de suporte . . . . . . . . . . . . . . . . . . . . . . . . . 27 6 2.2.2 2.3 Geração de montadores . . . . . . . . . . . . . . . . . . . . . . . . . 28 O trabalho proposto frente aos trabalhos correlatos . . . . . . . . . . . . . 31 3 A modelagem do microcontrolador PIC 16F84 33 3.1 Arquitetura do conjunto de instruções . . . . . . . . . . . . . . . . . . . . . 33 3.2 Caracterı́sticas gerais e peculiaridades do PIC 16F84 . . . . . . . . . . . . 35 3.2.1 Organização de memória . . . . . . . . . . . . . . . . . . . . . . . . 35 3.2.2 Banco de registradores . . . . . . . . . . . . . . . . . . . . . . . . . 36 3.3 Descrição funcional em ArchC . . . . . . . . . . . . . . . . . . . . . . . . . 38 3.4 Validação experimental do modelo . . . . . . . . . . . . . . . . . . . . . . . 39 4 A metodologia baseada em ADL 43 4.1 Visão geral da metodologia . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 4.2 Uma visão geral do montador parametrizável . . . . . . . . . . . . . . . . . 45 5 O uso de gramáticas na geração automática de ferramentas 5.1 46 Fundamentação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 5.1.1 Alfabeto (ou Vocabulário) . . . . . . . . . . . . . . . . . . . . . . . 46 5.1.2 Sentença (ou Palavra) . . . . . . . . . . . . . . . . . . . . . . . . . 46 5.1.3 Fechamento (closure) de um alfabeto . . . . . . . . . . . . . . . . . 47 5.1.4 Linguagem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 5.1.5 Gramática . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 5.1.6 Gramática Livre de Contexto (GLC) . . . . . . . . . . . . . . . . . 48 5.1.7 Gramática livre de contexto LL(1) . . . . . . . . . . . . . . . . . . 49 5.1.8 Geradores de analisadores léxico e sintático . . . . . . . . . . . . . . 49 5.2 Vantagens do uso de GLCs . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 5.3 O uso de GLC para a geração de montadores . . . . . . . . . . . . . . . . . 51 5.3.1 Gramáticas envolvidas . . . . . . . . . . . . . . . . . . . . . . . . . 51 5.3.2 Geração automática da gramática do montador . . . . . . . . . . . 52 6 Geração automática de ferramentas 6.1 55 A geração automática de montadores . . . . . . . . . . . . . . . . . . . . . 55 6.1.1 O fluxo de geração . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 6.1.2 Exemplo de geração de uma GLC . . . . . . . . . . . . . . . . . . . 57 6.2 6.3 6.1.3 Implementação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 6.1.4 Verificação de inconsistências . . . . . . . . . . . . . . . . . . . . . 61 A geração automática de pré-processadores . . . . . . . . . . . . . . . . . . 62 6.2.1 O papel do pré-processador . . . . . . . . . . . . . . . . . . . . . . 62 6.2.2 O fluxo de geração . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 6.2.3 Implementação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 Resultados experimentais . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 7 Conclusões e perspectivas 70 7.1 Produtos de trabalho . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 7.2 Contribuições e discussão . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 7.3 Trabalhos futuros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 7.4 Expectativa de impacto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 Referências bibliográficas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 Lista de Figuras 1.1 Relação desempenho/potência das alternativas de implementação 18 2.1 Regra de instrução em nML . . . . . . . . . . . . . . . . . . . . . . . . 28 3.1 Diagrama da organização do PIC 16F84 . . . . . . . . . . . . . . . . 35 3.2 Organização de memória do PIC 16F84 . . . . . . . . . . . . . . . . . 36 3.3 Registradores especı́ficos do PIC 16F84 . . . . . . . . . . . . . . . . . 37 3.4 Descrição ArchC de uma versão condensada do PIC 16F84 . . . . 38 3.5 Tamanho de código: PIC 16F84 x i8051 . . . . . . . . . . . . . . . . 41 3.6 Tempo de simulação: PIC 16F84 x i8051 . . . . . . . . . . . . . . . . 42 4.1 A metodologia de projeto adotada . . . . . . . . . . . . . . . . . . . . 44 4.2 O montador parametrizável . . . . . . . . . . . . . . . . . . . . . . . . 45 5.1 Definições regulares . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 5.2 Definição de tokens . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 6.1 O fluxo da geração de montadores . . . . . . . . . . . . . . . . . . . . 56 6.2 Exemplo de geração de GLC e lista de instruções . . . . . . . . . . 58 6.3 Gramática completa de uma descrição AC ISA em ArchC . . . . . 60 6.4 O gerador de pré-processadores . . . . . . . . . . . . . . . . . . . . . . 63 6.5 Definições reservadas de uma arquitetura fictı́cia . . . . . . . . . . . 64 6.6 Exemplo da classe AddressGenerator.h 9 . . . . . . . . . . . . . . . . 65 Lista de Tabelas 2.1 Principais ADLs e suas ferramentas . . . . . . . . . . . . . . . . . . . . . . 27 2.2 Técnicas de geração de montadores . . . . . . . . . . . . . . . . . . . . . . 32 3.1 Conjunto de instruções do PIC 16F84 . . . . . . . . . . . . . . . . . . . . . 34 3.2 Funcionalidades dos registradores especiais do PIC 16F84 . . . . . . . . . . 37 3.3 Caracterı́sticas dos benchmarks utilizados . . . . . . . . . . . . . . . . . . . 41 6.1 Tempos de geração do pré-processador e montador . . . . . . . . . . . . . . 67 6.2 Seleção de cores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 6.3 Tempos de geração do montador . . . . . . . . . . . . . . . . . . . . . . . . 68 6.4 Caracterı́sticas dos benchmarks . . . . . . . . . . . . . . . . . . . . . . . . 68 6.5 Tempos de pré-processamento e montagem de cada programa . . . . . . . . 69 10 Lista de Siglas µPs ADL ALU ASIC ASIP BNF CAD CPU EDA EEPROM FPGA FSR GALS HDL IP IR ISS MOPS mW NoC PC RISC RT SFR SiP SoC UMTS VHDL VLIW YACC Microprocessors Architecture Description Language Arithmetic-Logic Unit Application-Specific Integrated Circuit Application-Specific Instruction-Set Processor Backus-Naur Form Computer-Aided Design Central Processing Unit Electronic Design Automation Electrically Erasable Programmable Read-Only Memory Field Programmable Gate Array Function Selection Register Generator of Syntactic and Lexical Analyzers Hardware Description Language Intellectual Property Instruction Register Instruction-set simulator Millions of operations per second Miliwatt Network-on-chip Program Counter Reduced Instruction Set Computer Register Transfer Special Function Register System in a Package System-on-Chip Universal Mobile Telecommunication System Very High Speed Integrated Circuit Hardware Description Language Very Long Instruction Word Yet Another Compiler Compiler 11 Resumo GERAÇÃO AUTOMÁTICA DE FERRAMENTAS DE SUPORTE AO DESENVOLVIMENTO DE SOFTWARE EMBARCADO PARA ASIPs Leonardo Taglietti Fevereiro/2005 Orientador: Olinto José Varela Furtado Co-orientador: Luiz Cláudio Villar dos Santos Área de Conhecimento: Sistemas de Computação Palavras-chave: ADL, ASIP, assembler Número de Páginas: 76 Como resultado da evolução da Microeletrônica, é hoje possı́vel fabricar-se um sistema embarcado em um único circuito integrado ou System-on-Chip (SoC). Um SoC compõese de uma ou mais CPUs, memórias, meios de comunicação e blocos de propriedade intelectual ou Intelectual Property Blocks (IPs). Uma de suas alternativas de projeto é o uso de CPU dedicada, cujo conjunto de instruções é talhado para uma dada classe de aplicações, dando origem ao assim-chamado Application-Specific Instruction-Set Processor (ASIP). Como um ASIP não é um componente padrão, não há disponibilidade imediata de ferramentas de suporte ao desenvolvimento de seu software. Tais ferramentas devem ser geradas automaticamente, pois sua elaboração manual inviabilizaria o uso de ASIPs sob a pressão do time-to-market. A eficiente geração de ferramentas requer o uso de Linguagens de Descrição de Arquiteturas ou Architecture Description Languages (ADLs). A técnica proposta nesta dissertação representa uma das etapas de uma metodologia mais ampla. A metodologia vislumbra uma descrição ADL do ASIP como ponto de 12 partida tanto para a geração automática de ferramentas de suporte ao desenvolvimento de software embarcado, quanto para o fluxo de projeto do hardware. A principal contribuição desta dissertação é a concepção de um montador parametrizável. Dada uma descrição ADL da arquitetura de um ASIP, o efeito de montador parametrizável é obtido através da geração automática de um pré-processador e de um montador para a arquitetura descrita. A automação ampara-se em técnicas formais baseadas em Gramática Livre de Contexto (GLC) para a geração de parsers. A técnica proposta baseia-se em uma especificação unificada dos aspectos léxicos e sintáticos da linguagem e em um novo algoritmo para a geração de GLC. A eficiência da técnica é mostrada experimentalmente tanto para as ferramentas geradoras, quanto para as ferramentas geradas. Robustez e corretude são garantidas formalmente. A manutenibilidade e a extensibilidade do montador parametrizável são viabilizadas por um mecanismo de co-validação entre linguagem e gramática, bem como por mecanismos de verificação de expressões regulares. Vários experimentos foram realizados para assegurar a validação e avaliar a eficiência da técnica proposta. Nos experimentos, foram utilizados programas extraı́dos do benchmark do bem conhecido Projeto Dalton, os quais foram montados para três CPUs-alvo: PIC 16F84, PowerPC 405 e MIPS. A ADL adotada nesta dissertação é ArchC, que possui a caracterı́stica única de gerar modelos escritos em SystemC. Para a familiarização com a ADL, adotou-se o microcontrolador PIC 16F84, de uso bastante difundido, como estudo de caso. Assim, um dos produtos de trabalho desta dissertação é um modelo funcional daquele microcontrolador, devidamente validado. 13 Abstract AUTOMATIC GENERATION OF SUPORTING TOOLS FOR ASIP EMBEDDED SOFTWARE DEVELOPMENT Leonardo Taglietti February/2005 Adivisor: Olinto José Varela Furtado Co- Adivisor: Luiz Cláudio Villar dos Santos Area of Concentration: Design Automation Systems Keywords: ADL, ASIP, assembler Number of Pages: 76 As a result of the evolution of Microelectronics, it is possible today to design an embedded system in a single integrated circuit, which is known as System-on-Chip (SoC). A SoC is composed of one or more CPUs, memories, communication network and Intellectual Property Blocks (IPs). One of its design alternatives is the use of a dedicated CPU, whose instruction set is tailored to for one application class, leading to an Application-Specific Instruction-Set Processor (ASIP). Since an ASIP is not a standard component, supporting tools to its software development are not immediately available. Such tools must be automatically generated, otherwise its manual design would make impractical the use of ASIPs under the current time-to-market pressure. Efficient tool generation requires the use of Architecture Description Languages (ADLs). The technique proposed in this dissertation represents one of the steps of a broader methodology. The envisaged methodology adopts an ADL description of the ASIP as a 14 starting point not only for the automatic generation of supporting tools for embedded software development, but also for the hardware design flow. The main contribution of this dissertation is the design of a parameterizable assembler tool. Given an ADL description of the ASIP’s architecture, the effect of parameterizable assembler results from the automatic generation of pre-processing and assembling tools for the described architecture. Automation relies on formal techniques based on Context-Free Grammar (CFG) for parser generation. The proposed technique is based upon a unified specification of lexical and syntactic aspects of the language and on a novel algorithm for CFG generation. The technique’s efficiency was shown experimentally for both the generating and the generated tools. Robustness and correctness are guaranteed by the formal framework. Maintainability and extensibility are provided by a co-validation mechanism between language and grammar and by a regular expression verification mechanism. Several experiments were performed for validation and efficiency evaluation. Programs from the well-known Dalton Project benchmark were assembled for three target CPUs: PIC 16F84, PowerPC 405 e MIPS. The ADL adopted in this dissertation is ArchC, which has the unique feature of generating SystemC models. For acquaintance with the ADL, the well-known microcontroller PIC 16F84 was used as a case study. As a result, one of the dissertation’s work products is a functional model of that microcontroller, properly validated. 15 Capı́tulo 1 Introdução A tecnologia de Microeletrônica tem evoluı́do significativamente há mais de três décadas. Essa evolução é regida pela Lei de Moore, a qual prevê que, a cada 18 meses, dobra o número de transistores em um circuito integrado (CI), tornando-o cada vez mais complexo. Devido a esse crescimento, em progressão geométrica, os projetos de CIs tornam-se viáveis apenas se utilizadas ferramentas de Computer-Aided Design (CAD) ou Electronic Design Automation (EDA). Muitos produtos eletrônicos são sistemas integrados de hardware e software, formando os denominados embedded systems ou sistemas embutidos/embarcados. Um sistema embarcado é qualquer dispositivo que contenha um computador programável e que não seja utilizado ou entendido como um computador de propósito geral [Wol00]. Há uma grande variedade de aplicações que utilizam sistemas embarcados, tais como eletrodomésticos, automóveis, aviões, equipamentos médicos, automação industrial, sistemas de telecomunicações, etc. Atualmente, 79% dos processadores de alto desempenho no mercado são usados em sistemas embutidos [Mar03b]. Segundo Marwedel [Mar03b], os modelos de automóveis mais avançados da marca BMW contêm mais de 100 microprocessadores. 1.1 Alternativas de implementação Inicialmente, os sistemas embarcados eram construı́dos com seus componentes (chips) montados em placas de circuito impresso. A evolução tecnológica permitiu que um sistema embarcado pudesse ser acomodado em poucas pastilhas dentro de um único encapsula- 16 mento. Essa alternativa é denominada System in a Package (SiP). A continuidade dessa evolução tornou possı́vel o projeto de um sistema embarcado em um único circuito integrado, originando a noção de System-on-Chip (SoC). Um SoC pode agregar uma ou mais CPUs, blocos de propriedade intelectual ou Intelectual Property Blocks (IPs), memórias, unidades de entrada/saı́da, etc. A infraestrutura de comunicação entre IPs é, em geral, uma estrutura de barramentos ou pode ser uma rede em chip ou Network-on-a-Chip (NoC)[Dea01]. Além disso, um IP pode necessitar de parâmetros de operação ou configuração ou de um programa (caso de um processador). As CPUs padrão foram desenvolvidas originalmente para aplicações de propósitos gerais nos mercados de desktop e servidores. Como o conjunto de instruções de uma CPU padrão é projetado para atender os requisitos de uma larga faixa de aplicações, vários recursos do processador podem ficar ociosos ou sub-utilizados. Embora pouco ou nada contribuam para uma dada aplicação, tais recursos ociosos contribuem para o consumo de potência da CPU. Por isso, várias CPUs padrão (tais como PowerPC, MIPS e ARM) possuem versões projetadas para o mercado de sistemas embarcados, onde o consumo de potência pode ser reduzido desligando-se o relógio dos recursos ociosos, colocando a máquina em modos de operação de baixa potência ou permitindo a redução da tensão e da freqüência dinamicamente para minimizar o consumo de potência [Mar03b]. Para garantir desempenho adequado e baixo consumo de potência, uma das alternativas é o uso de uma CPU dedicada ou Application-Specific Instruction-Set Processor (ASIP). Um ASIP caracteriza-se por um conjunto de instruções talhado para uma classe especı́fica de aplicações. Como um ASIP não é um componente padrão, as ferramentas de suporte ao desenvolvimento de seu software embarcado não estão disponı́veis. Diante da pressão do time-tomarket, essa indisponibilidade de ferramentas torna imperativa sua geração automática, pois a elaboração manual inviabilizaria o uso de ASIPs. Para aplicações de alto desempenho e de alto volume de mercado, podem ser utilizados circuitos integrados de aplicação especı́fica ou Application-Specific Integrated Circuits (ASICs). ASICs são caracterizados por uma única aplicação e por isso não são programáveis, resultando em inflexibilidade e alto custo. 17 1.2 Requisitos de um sistema embarcado Segundo Marwedel [Mar03b], além dos requisitos funcionais e de qualidade de serviço, aos sistemas embarcados costumam ser impostas algumas restrições. As principais são: • Restrição de tamanho de código (devido à escassez de memória); • Restrição de consumo de potência e energia (devido à operação com bateria); • Restrições de tempo real (devido ao timing da aplicação); O consumo de potência e energia tem se mostrado como a restrição dominante. Por exemplo, a transmissão de dados através de telefones celulares com tecnologia UMTS resulta na exaustão da bateria em cerca de uma hora [Mar03b]. Figura 1.1: Relação desempenho/potência das alternativas de implementação A Figura 1.1, adaptada da original em [Mar03b], ilustra o compromisso entre a eficiência energética e a flexibilidade de diferentes alternativas de implementação: processador de uso geral, lógica reconfigurável e ASIC. O eixo das abscissas representa a escala de miniaturização das tecnologias de circuitos integrados (tamanho mı́nimo dos transistores). O eixo das ordenadas representa a eficiência energética, ou seja, o desempenho obtido por miliwatt (mW) de potência consumida. Note que a eficiência energética dos ASIPs é da mesma ordem de grandeza da alternativa em lógica reconfigurável. Observa-se que, para uma alternativa de implementação arbitrária, a miniaturização provoca aumento da eficiência energética. Por outro lado, para uma dada tecnologia, a 18 eficiência energética diminui com a flexibilidade da alternativa de implementação. Por exemplo, embora um processador de uso geral ofereça mais flexibilidade à alteração de funcionalidade de uma aplicação, sua eficiência energética é de uma ordem de magnitude inferior à uma implementada usando lógica reconfigurável. Por sua vez, o ASIC apresenta a maior eficiência energética, mas possui a menor flexibilidade, pois sua personalização é realizada em hardware não programável. É importante lembrar que o custo de desenvolvimento de circuitos integrados aumenta com a eficiência energética. Diante disso, o projeto de um ASIP justifica-se como um compromisso entre eficiência energética, flexibilidade e custo. 1.3 Fluxo de projeto e nı́veis de descrição Um componente de um sistema embarcado pode ser modelado em vários nı́veis de abstração [Gea02], tais como: • Nı́vel funcional: a funcionalidade é modelada sem considerar como o sistema será implementado. • Nı́vel comportamental: a funcionalidade é modelada independentemente da futura implementação, mas a temporização dos eventos na interface já possui precisão de ciclos. • Nı́vel RT (register-transfer): a modelagem reflete a estrutura do hardware em termos de registradores, unidades funcionais, barramentos e unidade de controle. A temporização dos eventos é precisa tanto na interface quanto na estrutura interna. • Nı́vel lógico: reflete a estrutura interna do componente em termos de portas lógicas e elementos de armazenamento. A temporização é ainda mais precisa que aquela descrita no nı́vel RT. O projeto de cada componente envolve refinamentos sucessivos de uma descrição mais abstrata para uma menos abstrata. Geralmente inicia-se com uma descrição puramente funcional, sem considerar como o sistema será implementado. Posteriormente, pode-se adicionar ao modelo outras caracterı́sticas, como por exemplo, precisão de ciclos. Sucessivos nı́veis vão sendo construı́dos e refinados, visando chegar a um modelo em nı́vel 19 RT, que costuma ser descrito em uma Linguagem de Descrição de Hardware ou Hardware Description Language (HDL). A indústria de EDA produz uma infinidade de ferramentas de projeto com entrada HDL, cuja utilização foi disseminada para a indústria de sistemas. VHDL e Verilog são HDLs fortemente estabelecidas na indústria de EDA e na indústria de sistemas. Algumas linguagens e extensões foram propostas visando aumentar o nı́vel de abstração do projeto de sistemas (System-Level Design). Este nı́vel de descrição de sistemas é suportado por SystemC [Sys04], uma extensão das bibliotecas padrão da linguagem C++, através da qual é também possı́vel descrever caracterı́sticas de sistemas embarcados, tais como paralelismo do hardware, tempo, separação entre funcionalidade e comunicação, etc. SystemC é considerada a linguagem mais promissora para a modelagem de sistemas embarcados, especialmente nos mais altos nı́veis de abstração [Mar03a]. Em princı́pio, qualquer componente digital de um sistema embarcado pode ser descrito em SystemC no nı́vel funcional. Entretanto, um modelo descrito em SystemC admite tantos estilos de descrição que inviabiliza a geração automática eficiente de ferramentas de suporte. Essa dificuldade é contornada com a introdução de Linguagens de Descrição de Arquiteturas ou Architecture Description Languages (ADLs). Uma ADL é uma linguagem cujas primitivas permitem a descrição do conjunto de instruções de uma CPU e, possivelmente, de algumas caracterı́sticas e parâmetros de sua organização (comprimento da palavra de instrução, códigos de operações, bancos de registradores, memórias, etc). Observa-se que o uso de ADLs torna mais pragmática e eficiente a geração automática de ferramentas de suporte ao desenvolvimento de software embarcado, além de facilitar o projeto do hardware do ASIP. 1.4 Contexto desta dissertação O projeto de um sistema embarcado envolve o projeto do hardware e o desenvolvimento do software. Como o software não pode ser depurado sem uma plataforma de hardware, as metodologias de projeto antigas consistiam no projeto do hardware, seguido do projeto do software e da chamada integração software-hardware. Nesta abordagem de projeto, a detecção tardia de erros pode resultar em vários ciclos de re-projeto. Diante das necessidades de redução de custo de engenharia não recorrente [Wol00] e da 20 pressão do time-to-market, uma metodologia de co-projeto de hardware e software (HW/SW Co-design) tornou-se mandatória. A técnica de co-projeto requer que o software seja desenvolvido e depurado antes do hardware estar disponı́vel. Para isso, o software deve ser testado em um modelo executável do hardware. Assim, o co-projeto de hardware e software pode amparar-se em ADLs para a geração de modelos executáveis, permitindo vislumbrar uma metodologia de projeto onde uma descrição ADL é o ponto de partida, em nı́vel funcional, do fluxo de projeto de um ASIP. As técnicas abordadas nesta dissertação situam-se no contexto de uma metodologia de suporte ao uso de ASIPs em SoCs. A metodologia vislumbrada tem os seguintes pressupostos: • A descrição ADL do ASIP é o ponto de partida para o fluxo de projeto do hardware (manual ou automático). • A descrição ADL do ASIP é o ponto de partida para a geração automática de modelos funcionais e ferramentas de suporte ao desenvolvimento de software embarcado, tais como montador, compilador cruzado, simulador do conjunto de instruções, etc. Esta dissertação situa-se no âmbito do segundo pressuposto, conforme descrito na próxima seção. 1.5 Foco e contribuições da dissertação A principal contribuição desta dissertação é a concepção e a implementação de um programa montador parametrizável a partir de uma descrição ADL. O montador parametrizável baseado em ADL é obtido a partir da geração automática de um pré-processador e de um montador para a arquitetura do conjunto de instruções representada na descrição ADL. Assim, sempre que uma nova instrução for adicionada ao conjunto de instruções de um ASIP, um novo programa montador pode ser produzido automaticamente. Para fins de estudo de caso, foi desenvolvido um modelo funcional do microcontrolador PIC 16F84 [Inc04b], de uso bastante difundido, para fazer o papel de um core parametrizável. Além desse modelo, foram também utilizados modelos do MIPS [Arc04] e do PowerPC 405 [Fea04], para fins de validação e avaliação do montador parametrizável. 21 Esta dissertação está situada no âmbito do Projeto DESERT (Desenvolvimento de Ferramentas para Sistemas Embutidos de Tempo Real), o qual visa contribuir com novas técnicas de EDA para o desenvolvimento de sistemas embarcados. A execução das atividades de pesquisa é amparada por bolsa de mestrado do Conselho Nacional de Desenvolvimento Cientı́fico e Tecnológico (CNPq), no âmbito do Programa Nacional de Microeletrônica (PNM). 1.6 Organização da dissertação A presente dissertação é assim organizada: no Capı́tulo 2 são discutidos alguns trabalhos correlatos, com foco na geração automática de ferramentas a partir de ADLs. Uma breve descrição do estudo de caso, baseada no microcontrolador PIC 16F84, é discutida no Capı́tulo 3. Este capı́tulo discute também a modelagem do PIC implementada em ArchC e mostra os resultados experimentais obtidos a partir deste modelo. O Capı́tulo 4 detalha a metodologia baseada em ADL que norteia a dissertação, delimitando seu escopo. No Capı́tulo 5, descreve-se o papel das gramáticas na geração de parsers. O Capı́tulo 6 descreve as técnicas de geração de montadores e pré-processadores. Neste capı́tulo também são mostrados os resultados experimentais obtidos a partir das ferramentas desenvolvidas. As conclusões e perspectivas de trabalhos futuros são apresentadas no Capı́tulo 7. 22 Capı́tulo 2 Trabalhos correlatos As linguagens de descrição de arquiteturas existentes variam muito em sua expressividade, de acordo com os objetivos a que se propõem. As caracterı́sticas estruturais, comportamentais e de sintaxe influenciam diretamente os métodos de geração de ferramentas a partir destas ADLs, podendo dificultar e até mesmo inviabilizar a completa geração destas ferramentas. Segundo Hadjiyiannis [Hea97a], algumas caracterı́sticas desejáveis em uma ADL são: • Representação de uma grande variedade de arquiteturas. • Definição de restrições que definem grupos de operações válidas dentro de uma instrução. • Fácil modificação do compilador e/ou arquitetura. • Suporte a geração automática de montador, simulador e gerador de código. • Informações adequadas para otimizações de código. Em seguida, as ADLs mais difundidas são analisadas em termos de suas principais caracterı́sticas. 2.1 2.1.1 Um panorama das ADLs nML nML foi desenvolvida na Technical University of Berlin (TUB). Seu desenvolvimento baseou-se na observação das informações que estão disponı́veis nos manuais de processa23 dores, tais como lista de instruções, operações entre registradores, sintaxe da linguagem de montagem, modos de endereçamento, etc. Em nML, a estrutura da arquitetura é descrita junto com o comportamento das instruções, misturando informações estruturais e comportamentais. A falta de flexibilidade na descrição de comportamentos traz inúmeras dificuldades no uso de nML [Hea97b]. A versão original de nML não oferecia suporte a self-modifying code 1 e instruções multi-ciclos. O conjunto de instruções é descrito por uma gramática com atributos. Ações semânticas de qualquer instrução podem ser compostas de vários fragmentos distribuı́dos na árvore da gramática, permitindo compartilhar comportamentos, codificações e sintaxe entre várias instruções. Em nML, a execução de um programa tem por objetivo alterar o conteúdo de registradores. A partir de descrições nML, projetistas da TUB e de outros grupos de pesquisa desenvolveram ferramentas, tais como geradores de código e simuladores. 2.1.2 LISA LISA foi desenvolvida para permitir a geração automática de simuladores, utilizando a técnica de simulação compilada, com precisão de ciclos e de bits. Uma contribuição inicial desta ADL foi a descrição de pipeline em nı́vel de operação e o modelo de sequenciamento. A descrição de uma arquitetura em LISA envolve declarações de recursos e de operações, sendo estas os elementos básicos da linguagem. As operações são divididas em várias seções de acordo com diferentes propriedades do sistema e representam a visão do programador quanto à estrutura, conjunto de instruções e comportamento da arquitetura. Memórias, registradores e pipelines fazem parte dos recursos disponı́veis na arquitetura. O pipeline possui execução sı́ncrona e as operações são atribuı́das a estágios de pipeline. Uma nova versão de LISA [Pea99] permite a geração automática de simuladores e montadores para diversas classes de arquitetura. LPDP [Sea02] é uma extensão de LISA voltada para o projeto de ASIPs, tendo por base uma descrição LISA. LPDP possibilita a geração de ferramentas de desenvolvimento de software. Entre as extensões disponibilizadas estão a geração automática do back-end de um compilador C e de um modelo sintetizável em HDL. 1 Código que pode modificar-se dinamicamente. 24 O modelo de memória inclui todas as memórias e registradores do sistema. O modelo de recursos descreve a estrutura do hardware, determinando suas restrições. Tais informações são utilizadas pelo compilador para realizar o escalonamento das instruções, possibilitando assim o compartilhamento de recursos. Extensões de LISA [Bea04] recentemente publicadas possibilitam a geração de compiladores C. As informações necessárias são extraı́das de uma descrição LISA e as outras são informadas manualmente pelo usuário. O arquivo de saı́da é uma descrição no formato CGD (Code Generator Description) [LIS04], para a qual já existem ferramentas de geração de compiladores C. 2.1.3 EXPRESSION A ADL EXPRESSION é voltada para a descrição de arquiteturas para SoCs, através da qual é possı́vel gerar ferramentas automaticamente. Expression permite a especificação de sistemas de memória e, seguindo o mesmo paradigma de LISA, mistura informações estruturais e comportamentais. As técnicas encontradas em [Gea99] possibilitam a geração automática de compiladores. Mishra [Mea01] introduziu uma metodologia de projeto baseada em abstração funcional, na qual foram definidas funções parametrizadas para unidades funcionais de arquiteturas reconfiguráveis (unidade de busca, predição de desvios, etc) oferecendo suporte para a geração de ferramentas. 2.1.4 ISDL A linguagem ISDL (Instruction Set Description Language for Retargetability) é uma ADL comportamental e foi apresentada juntamente com um gerador automático de montadores. Mesmo sendo especialmente voltada para arquiteturas do tipo VLIW (Very Long Instruction Word ), ISDL foi projetada com capacidade de redirecionamento automático de compiladores, possibilitando descrever várias classes de arquiteturas. As descrições da parte estrutural, usadas para gerar modelos de hardware, são extraı́das do simulador do conjunto de instruções e das descrições de operação (geralmente no nı́vel RT). Por exemplo, as informações de latência e atraso modeladas no simulador são cruciais para a geração destes modelos. Algumas ferramentas existentes para ISDL são: gerador de geradores de código, gera25 dor de simuladores e gerador de modelos de hardware. Segundo Hadjiyiannis [Hea97a], não é possı́vel descrever instruções multi-ciclos de tamanho variável, sendo esta uma grande restrição da ADL. 2.1.5 ArchC Tornada pública recentemente e adotada como ponto central para o desenvolvimento desta dissertação, ArchC [Rig04] destaca-se por ser a primeira ADL que gera simuladores (modelos executáveis) escritos em SystemC [Sys04]. Os focos iniciais desta ADL são a simulação e a co-verificação. Entretanto, foi projetada também para oferecer suporte a outras ferramentas que ainda estão em fase de desenvolvimento, tais como montadores, ligadores, compiladores e geradores de código. ArchC permite a declaração de recursos da arquitetura (denominado AC ARCH), tais como registradores, bancos de registradores e memórias. Além disso, é possı́vel definir o tamanho da palavra de dados da arquitetura, estágios de pipeline, etc. Os registradores podem ser associados a formatos de instrução ou ao tamanho da palavra de dados da arquitetura. A descrição do conjunto de instruções da arquitetura (denominado AC ISA) fornece detalhes sobre formatos de instrução (campos, tamanhos, etc.), sintaxe assembly e códigos operacionais. Um exemplo de descrição ArchC será mostrado na Seção 3.3. ArchC possui um pré-processador composto por um parser, um gerador de simuladores e um geradores de decodificadores. A partir das informações extraı́das das descrições AC ISA e AC ARCH, o pré-processador ArchC gera classes C++ e/ou módulos SystemC que farão parte do código fonte do simulador. Os comportamentos das instruções são implementados manualmente. O decodificador recebe uma seqüência de bits lidos da memória e utiliza os códigos operacionais para identificar qual instrução deve ser executada. O simulador do conjunto de instruções, gerado a partir de uma descrição ArchC, pode ser integrado a outros modelos, sendo esta uma das grandes vantagens de sua utilização. ArchC é licenciada sob a GNU Lesser General Public License (LGPL) e encontra-se disponı́vel em [Rig04]. Uma comparação entre ADLs, extraı́da de [Rig04], é apresentada na Tabela 2.1. Nesta tabela, a letra F denota a não disponibilidade atual de duas ferramentas na versão atual do pacote ArchC, embora haja pesquisas em andamento para esse fim. 26 Tabela 2.1: Principais ADLs e suas ferramentas Caracterı́sticas LISA EXPRESSION nML ISDL ArchC Conjunto de instruções * * * * * Precisão de ciclos * * * Suporte a multi-ciclo * * * Suporte a pipeline * * * Hierarquia de memória * * * Emulação de sistema operacional * Hierarquia de comportamentos * Co-verificação * Geração de simuladores escritos em SystemC * Geração de montadores * * Simulação compilada * * Redirecionamento de compiladores * * 2.2 2.2.1 * F * * F Abordagens para a geração de ferramentas Ferramentas de suporte A partir de código-fonte escrito em linguagem de alto nı́vel (geralmente C/C++), é possı́vel gerar código executável para uma arquitetura alvo com o auxı́lio de compiladores cruzados (cross-compilers). Geralmente, é realizada a alteração/construção do back-end de algum compilador existente a partir da arquitetura desejada. A crescente demanda por cross-compilers exige sua completa geração automática ou, de maneira parcial, a geração automática de seu back-end. Esta última alternativa é largamente utilizada, principalmente quando se trata de compiladores com código-fonte aberto, como o GCC da GNU [GNU04]. A adoção de determinada metodologia para geração de ferramentas de software está fortemente relacionada com o tipo de projeto. No projeto de sistemas embarcados, fatores como classes de arquiteturas, linguagens de programação, ADLs e HDLs devem ser considerados. Por exemplo, apesar de a ADL nML possibilitar a descrição de uma grande variedade de arquiteturas, suas caracterı́sticas especı́ficas podem subsidiar o crescimento da complexidade no desenvolvimento de ferramentas. Na descrição em nML mostrada na 27 Figura 2.1 (reproduzida de [Hea97b]), a estrutura da arquitetura é definida juntamente com informações do nı́vel RT (seção action). Figura 2.1: Regra de instrução em nML A complexidade das caracterı́sticas apresentadas motivam a geração de descrições intermediárias para facilitar o processo de geração das ferramentas. Entretanto, nem sempre estão completas. Por exemplo, o assembler apresentado por Hartoog [Hea97b] não apresenta suporte a labels, declarações de variáveis e diretivas. A adoção de uma determinada ADL que atenda as necessidades dos desenvolvedores de ferramentas é um fator que deve ser considerado. Na ADL ArchC, por exemplo, as informações do nı́vel RT e da arquitetura do conjunto de instruções estão definidas separadamente, facilitando o desenvolvimento de ferramentas. 2.2.2 Geração de montadores As técnicas de geração de montadores vem sendo pesquisadas desde a década de 70. Primeiramente, eram adotadas técnicas adhoc baseadas na similaridade entre as linguagens assembly [Wea87]. Posteriormente, técnicas formais baseadas em gramáticas foram introduzidas, possibilitando a geração automática do parser da linguagem assembly [Tra87]. Entretanto, ainda eram necessárias intervenções manuais para a definição da gramática. Nas descrições de arquiteturas através de uma HDL, são inseridas informações desnecessárias para a geração de montadores. Tal fato contribuiu para o aparecimento das representações intermediárias, contendo somente informações relevantes para a geração de ferramentas, tais como assemblers. Paralelamente, esta evolução colaborou para a geração automática de gramáticas, e conseqüentemente, dos parsers a partir delas gerados. Com o surgimento das ADLs, as informações relevantes para a geração automática de ferramentas são capturadas diretamente pelo parsing da ADL [Hea97a] [Bea04] [Fre93] 28 [Pea99] [Hea99]. Os simuladores (modelo executável) gerados a partir de ADLs precisam ser amparados por montadores para viabilizar o processo de simulação. Daı́ surge a necessidade de geração automática de montadores. Baseados em técnicas formais para a realização do parsing e geração de código, a maioria dos geradores de montadores pesquisados [Hea97a] [Kum00] [CF90] produzem as definições léxicas com a notação usada no gerador de analisadores léxico Lex [GNU04], e as definições sintáticas com a notação usada no gerador de analisadores sintáticos Bison [GNU04] ou Yacc [YAC04]. O Yacc, utilizado por exemplo nas implementações em [Hea97a], é um dos mais difundidos geradores de parsers. Entretanto, é limitado à técnica de análise sintática LALR(1) e não possui um mecanismo de co-validação entre linguagem e gramática. Alguns fatores limitam e dificultam o processo de geração de montadores, tais como: • heterogeneidade das arquiteturas; • mistura de informações estruturais e comportamentais na descrição ADL; • sintaxe assembly; Em [Kum00], é apresentado um gerador de montadores para a linguagem Sim-nML (uma extensão de nML). Para construir o parser do montador, são gerados arquivos Lex e Yacc. Opcionalmente, o gerador poderá incluir um arquivo com informações de realocação em tempo de ligação para a máquina especı́fica. Uma descrição em Sim-nML deve ser convertida para um formato intermediário e posteriormente armazenada em outro arquivo, o qual será a entrada principal do gerador de montadores. Este gerador possui tabelas que contêm, entre outras informações, atributos, regras, sintaxes e tipos de dados, e gera como saı́da um arquivo no formato ELF [ELF04]. Estas informações opcionais são definidas separadamente em um arquivo de configuração. Um gerador de montadores desenvolvido para a ADL ISDL [Hea97a] produz arquivos com padrão Lex e Yacc, a partir dos quais são gerados o analisador léxico e o parser do montador. O analisador léxico inclui, em sua tabela de sı́mbolos, os seguintes componentes: • Tipos de dados pré-definidos; • Nomes de operações; 29 • Tokens da definição global ISDL; • Labels (endereços simbólicos); Antes da realização do parsing, um script invoca um pré-processador C para resolução de macros, pseudo-instruções e inclusões (links), gerando como saı́da um arquivo com código assembly. O montador processa este arquivo assembly em dois passos. Primeiramente, o gerenciador do parser presente no arquivo de definições Yacc realiza inicializações no arquivo de entrada e preenche uma tabela de sı́mbolos. No passo seguinte, realiza a resolução de labels e conclui a montagem baseada nas informações obtidas da descrição ISDL. Ferguson [Fer66] apresenta um gerador de montadores chamado de meta-assembler que, ao invés de partir de uma descrição de máquina, recebe como entrada declarações de macros, as quais empacotam campos em palavras através de manipulações de bits. O meta-assembler implementa cada instrução através de uma macro, inserindo algumas facilidades para incluir e referenciar operandos na palavra de instrução. O tamanho da palavra de dados e algumas caracterı́sticas da arquitetura são representados por variáveis globais. A geração de um novo assembler ocorre através da definição e redefinição de macros para as instruções, caracterizando o meta-assembler como um processador de macros. Uma vantagem desta técnica é a padronização do software que realiza a avaliação de expressões, manipulação de tabelas de sı́mbolos e análise sintática. Apesar disso, Wick [Wic75] apresenta as seguintes desvantagens do meta-assembler : • Baixo desempenho no processo de montagem; • Ineficiência e inflexibilidade; • Difı́cil sustentação de hipótese sobre as classes de máquinas que podem ser tratadas; A técnica apresentada por Wick [Wic75] baseia-se em tradução dirigida pela sintaxe, com foco principal no processo de geração de código. Após análise de montadores existentes, o autor obteve um modelo genérico baseado em caracterı́sticas padrão. As estruturas de dados são construı́das a partir de informações especı́ficas da máquina, tais como formatos, opcodes e operandos. 30 Em Abbaspour [Aea02], o reconhecimento de programas escritos em linguagem assembly baseia-se em definições especı́ficas, utilizando caracteres especiais para representação de operandos, tais como registradores e valores imediatos. Portanto, o reconhecimento léxico e sintático não é realizado através de software gerado a partir do Lex e Yacc/Bison. Além disso, não é utilizado o formalismo Backus-Naur Form (BNF) para descrever a sintaxe da linguagem. A técnica apresentada pelo autor possui foco na geração da Aplication Binary Interface (ABI) para diferentes ADLs, realizando o redirecionamento da saı́da do GNU assembler gas. Porém, não ficam evidentes as técnicas utilizadas para a geração do código fonte do montador. 2.3 O trabalho proposto frente aos trabalhos correlatos A partir da análise de trabalhos correlatos, verificou-se o uso comum de gramáticas como a técnica formal adotada nas implementações. As gramáticas são usadas para a geração de parsers que reconheçam descrições em ADLs, arquivos de configurações e programas escritos em linguagem de montagem. Por exemplo, a definição de valores de campos ou registradores no formato hexadecimal pode ser usada para gerar a representação léxica destes valores, fazendo com que o montador gerado reconheça programas escritos em linguagem assembly com operandos neste formato de numeração. A partir de uma descrição em ADL, é possı́vel extrair os tokens e as regras sintáticas da linguagem, permitindo a geração automática da gramática que representa a linguagem assembly da arquitetura descrita e, posteriormente, a geração automática do parser a partir da gramática gerada. Os conceitos, caracterı́sticas e vantagens do uso de gramáticas são apresentadas no Capı́tulo 5. O gerador de montadores apresentado por Kumari [Kum00] exige a definição de macros juntamente com a descrição ADL. O autor afirma que se for usado como entrada um arquivo gerado por um cross-compiler do PowerPC 603, as informações sobre pseudoinstruções e macros deverão ser manualmente substituı́das por instruções nativas. O processo de montagem pode ser realizado em único passo durante o parsing de um programa assembly. Entretanto, este processo pode ser amparado por funções especı́ficas, tais como no montador criado por Hadjiyiannis [Hea97a]. Neste caso, a montagem é realizada em dois passos e o processamento de labels é realizado por funções especı́ficas. A Tabela 2.2 compara algumas caracterı́sticas envolvidas no processo de geração de 31 montadores. A coluna denominada ASMGen representa o gerador de montadores desenvolvido nesta dissertação. Caracterı́sticas não suportadas são denotadas pela letra “N”; caracterı́sticas presentes são indicadas pela letra “S”. Tabela 2.2: Técnicas de geração de montadores Caracterı́sticas e suportes Kumari[Kum00] ASMGen Gerador de analisador léxico Lex [LEX04] GALS [Ges04] Gerador de parser Yacc [YAC04] GALS [Ges04] Palavras-chave Arquivo especı́fico (separado) Desnecessário Entrada para o gerador de Arquivo intermediário, gerado Descrição ArchC montadores a partir de uma descrição Sim-nML Pré-processador S S Tamanho de instrução S S Formato de instrução S S Representação binária S N Suporte a labels S S O gerador de montadores aqui proposto assume que todas as instruções sejam nativas. Porém, como o uso de pseudo-instruções e macros é usual, um gerador de préprocessadores foi desenvolvido. Tal gerador produz um pré-processador capaz de expandir macros, substituir pseudo-instruções por instruções nativas, calcular endereços-alvo de desvio, etc. Assim, a adoção de um módulo pré-processador simplifica o processo de geração do montador. Para a geração de parsers, foi adotado o GALS [Ges04], um gerador de analisadores léxico e sintático desenvolvido na Universidade Federal de Santa Catarina. Em seu ambiente de desenvolvimento, é possı́vel especificar os aspectos léxicos e sintáticos de maneira unificada. Além da técnica de análise sintática LALR(1) presente no Yacc, o GALS suporta também as técnicas SLR(1), LR(1) e preditiva LL(1) [Aea88]. Uma das mais importantes caracterı́sticas do GALS é a disponibilidade de um simulador para a co-validação entre linguagem e gramática, bem como mecanismos de depuração de expressões regulares. Tais caracterı́sticas resultam na manutenibilidade e extensibilidade do gerador de montadores. 32 Capı́tulo 3 A modelagem do microcontrolador PIC 16F84 Este capı́tulo descreve sucintamente a arquitetura e a organização do microcontrolador PIC (Seções 3.1 e 3.2), adotado como estudo de caso. Além disso, o capı́tulo apresenta uma versão condensada da descrição funcional do PIC em ArchC (Seção 3.3). A Tabela 3.1 e as figuras desta seção são reproduções das originais, retiradas do manual do microcontrolador [Inc04b]. Ao final, o capı́tulo relata a validação do modelo, descrevendo os resultados experimentais. 3.1 Arquitetura do conjunto de instruções O PIC é um microcontrolador da famı́lia RISC que adota a arquitetura Harvard, sucintamente mostrada na Figura 3.1. Sua arquitetura é baseada em acumulador (8 bits), ou seja, um dos operandos é sempre armazenado no acumulador (denotado pela letra W). A Tabela 3.1 mostra o conjunto das 35 instruções do PIC, divididas em 3 diferentes formatos, baseados nas seguintes operações: • Operações orientadas a byte: existem 18 instruções mapeadas para este formato. As instruções movwf e clrf possuem apenas um operando e as instruções nop e clrw não possuem operandos. Todas as instruções restantes possuem dois operandos. • Operações orientadas a bit: apenas 4 instruções são mapeadas para este formato, a partir das quais é possı́vel testar e manipular, em nı́vel de bit, o conteúdo do banco 33 de registradores do PIC. Por exemplo, através das instruções btfsc e btfss realizam-se os desvios condicionais. • Operações de controle/literal: através das instruções mapeadas para este formato, realizam-se operações de controle do hardware do microcontrolador e também a inserção de valores (imediatos) na memória de dados. As instruções call, goto, retlw, return e retfie são utilizadas em desvios incondicionais. Tabela 3.1: Conjunto de instruções do PIC 16F84 Mnemonic Operands ADDWF f,d ANDWF f,d CLRF f CLRW COMF f,d DECF f,d DECFSZ f,d INCF f,d INCFSZ f,d IORWF f,d MOVF f,d MOVWF f NOP RLF f,d RRF f,d SUBWF f,d SWAPF f,d XORWF f,d BCF f,b BSF f,b BTFSC f,b BTFSS f,b ADDWF f,d ANDWF f,d CLRF f CLRW COMF f,d DECF f,d DECFSZ f,d INCF f,d INCFSZ f,d IORWF f,d MOVF f,d MOVWF f NOP RLF f,d RRF f,d SUBWF f,d SWAPF f,d XORWF f,d Description Cycles 14-Bit Opcode MSb LSb BYTE-ORIENTED FILE REGISTER OPERATIONS Add W and f 1 00 0111 dfff ffff AND W with f 1 00 0101 dfff ffff Clear f 1 00 0001 1fff ffff Clear W 1 00 0001 0xxx xxxx Complement f 1 00 1001 dfff ffff Decrement f 1 00 0011 dfff ffff Decrement f, Skip if 0 1(2) 00 1011 dfff ffff Increment f 1 00 1010 dfff ffff Increment f, Skip if 0 1(2) 00 1111 dfff ffff Inclusive OR W with f 1 00 0100 dfff ffff Move f 1 00 1000 dfff ffff Move W to f 1 00 0000 1fff ffff No Operation 1 00 0000 0xx0 0000 Rotate Left f through Carry 1 00 1101 dfff ffff Rotate Right f through Carry 1 00 1100 dfff ffff Subtract W from f 1 00 0010 dfff ffff Swap nibbles in f 1 00 1110 dfff ffff Exclusive OR W with f 1 00 0110 dfff ffff BIT-ORIENTED FILE REGISTER OPERATIONS Bit Clear f 1 01 00bb bfff ffff Bit Set f 1 01 01bb bfff ffff Bit Test f, Skip if Clear 1(2) 01 10bb bfff ffff Bit Test f, Skip if Set 1(2) 01 11bb bfff ffff LITERAL AND CONTROL OPERATIONS Add W and f 1 00 0111 dfff ffff AND W with f 1 00 0101 dfff ffff Clear f 1 00 0001 1fff ffff Clear W 1 00 0001 0xxx xxxx Complement f 1 00 1001 dfff ffff Decrement f 1 00 0011 dfff ffff Decrement f, Skip if 0 1(2) 00 1011 dfff ffff Increment f 1 00 1010 dfff ffff Increment f, Skip if 0 1(2) 00 1111 dfff ffff Inclusive OR W with f 1 00 0100 dfff ffff Move f 1 00 1000 dfff ffff Move W to f 1 00 0000 1fff ffff No Operation 1 00 0000 0xx0 0000 Rotate Left f through Carry 1 00 1101 dfff ffff Rotate Right f through Carry 1 00 1100 dfff ffff Subtract W from f 1 00 0010 dfff ffff Swap nibbles in f 1 00 1110 dfff ffff Exclusive OR W with f 1 00 0110 dfff ffff Status Affected C,DC,Z Z Z Z Z Z Z Z Z C C C,DC,Z Z C,DC,Z Z Z Z Z Z Z Z Z C C C,DC,Z Z Todas as instruções do PIC têm um tamanho fixo de 14 bits e a palavra de dados é composta de 8 bits. Com exceção das instruções de desvio, que gastam dois ciclos de clock, todas as instruções restantes consomem um único ciclo de clock. A coluna Status 34 Affected, presente na Tabela 3.1, representa os bits do registrador STATUS que são afetados após a execução de uma instrução. O Capı́tulo 6 detalha a influência de cada instrução na implementação do gerador de montadores. 3.2 Caracterı́sticas gerais e peculiaridades do PIC 16F84 A Figura 3.1(adaptada da original [Inc04b]) apresenta o diagrama da organização do PIC 16F84. As organizações de memória e de registradores são detalhadas em subseções. Figura 3.1: Diagrama da organização do PIC 16F84 3.2.1 Organização de memória O PIC 16F84 possui memória de programa interna com tamanho de 1024 bytes, e a memória de dados têm capacidade de armazenar até 68 bytes, possibilitando expansão. A memória EEPROM, que é mapeada indiretamente na memória de dados, pode armazenar 35 até 64 bytes. A Figura 3.2 mostra esta organização. Figura 3.2: Organização de memória do PIC 16F84 O Program Counter (PC) é um registrador de 13 bits, manipulado automaticamente pelo hardware do microcontrolador. Está disponı́vel uma pilha de 8 nı́veis implementada em hardware, a qual é manipulada diretamente pelo hardware após a execução das instruções de desvio call, return, retfie e retlw. O PIC 16F84 possui quatro fontes de interrupções, que são ativadas por recursos internos ou externos ao chip, como por exemplo, timers, operações de entrada/saı́da e escrita de dados na memória EEPROM. Os vetores de interrupção e de reset estão localizados em endereços fixos no espaço de memória do usuário. 3.2.2 Banco de registradores O PIC possui 15 registradores de uso especı́fico (SFRs), os quais são mapeados em memória e possuem endereços fixos. Por exemplo, o registrador PC localiza-se entre os SFRs. Nas instruções de desvio, o endereçamento direto é realizado a partir do Registrador de Instruções (IR) e o endereçamento indireto é auxiliado pelo registrador especı́fico FSR. Maiores detalhes podem ser encontrados no manual do microcontrolador [Inc04b]. 36 A Figura 3.3 exibe o banco de registradores do PIC. Figura 3.3: Registradores especı́ficos do PIC 16F84 A funcionalidade de cada registrador mostrado na Figura 3.3 é resumida na Tabela 3.2. Tabela 3.2: Funcionalidades dos registradores especiais do PIC 16F84 Registrador especı́fico Funcionalidade OPTION e TMR0 controle de timers PCL byte menos significativo do PC STATUS registro de operações da ALU FSR endereçamento indireto PORTA, PORTB, TRISA, TRISB destinados à operações de I/O EEDATA, EEADR, EECON1, manipulação de dados na EECON2 memória EEPROM PCLATH 5 bits mais significativos do PC INTCON controle de interrupções 37 3.3 Descrição funcional em ArchC A Figura 3.4 mostra um exemplo da descrição funcional do modelo do microcontrolador PIC 16F84, desenvolvido no âmbito desta dissertação. Como a descrição da arquitetura do conjunto de instruções do PIC é extensa, a figura apresenta uma versão condensada da descrição original. Figura 3.4: Descrição ArchC de uma versão condensada do PIC 16F84 38 A descrição mostrada na Figura 3.4 consiste essencialmente em quatro seções, que descrevem diferentes aspectos da arquitetura do conjunto de instruções. A descrição possui declarações de quatro diferentes formatos: Format Byte, Format Bit, Format Literal e Format Control, mostrados na Seção 1. Na Seção 2 ocorre a associação de cada instrução com seu devido formato. Visando a definição de caracterı́sticas sobre modos de endereçamento das instruções de desvio, foram especificadas duas palavras reservadas: ac addr mode A (modo de endereçamento absoluto) e ac addr mode R (modo de endereçamento relativo). Através da Seção 3, associa-se cada instrução de desvio ao seu respectivo modo de endereçamento. Além disso, é definido o campo do formato da instrução de desvio que possui os bits referentes ao endereço, cuja informação é necessária para a geração de ferramentas de software básico. Nesta dissertação, especificamente, são utilizadas para a geração de montadores e pré-processadores. As declarações contidas na Seção 3 não estão definidas na gramática da linguagem ArchC, e portanto, devem ser comentadas com “//” antes da geração do simulador (modelo executável) a partir desta descrição. Na Seção 4, denominada ISA CTOR (construtor), é definida a sintaxe assembly de cada instrução, bem como os códigos operacionais. 3.4 Validação experimental do modelo a) Configuração experimental Para a geração do simulador, utilizou-se a ADL ArchC, versão 0.8.2. O compilador PIC usado denomina-se PCWr (PIC C Compiler [Inc04a]), versão 3.182, com IDE versão 3.41. Os códigos assembly gerados pelo PCW foram submetidos a um montador gerado automaticamente (Seção 6.3). b) Procedimentos experimentais Inicialmente, as instruções descritas no modelo funcional do PIC 16F84 foram testadas e depuradas individualmente, por meio de expressões lógico-aritméticas. Deficiências encontradas foram imediatamente corrigidas. Testes mais avançados foram realizados 39 utilizando pequenos programas escritos em assembly. Posteriormente, experimentos envolvendo programas mais complexos foram amparados pelo compilador PCW (CCS) e pelo montador do PIC 16F84 gerado automaticamente (a ser descrito no Capı́tulo 6). Alguns exemplos são os programas envolvendo chamadas de rotinas e o algoritmo de ordenação Sort. Paralelamente, realizou-se um experimento usando o exemplo Belt-controller [Wol00]. Como o modelo do PIC não possui funcionalidades de entrada e saı́da, os estı́mulos necessários para simular o exemplo foram inseridos juntamente com o código do programa. Em seguida, uma validação mais ampla foi realizada através de experimentos baseados em benchmarks extraı́dos do Projeto Dalton [Pro04], cujos dados serão apresentados ainda nesta seção. O conjunto de benchmarks escolhido permitiu exercitar operações freqüentes em software embarcado, tais como operações básicas sobre inteiros, emulação de ponto flutuante, conversões de tipo e operações sobre ponteiros. Além disso, foram testadas e validadas caracterı́sticas peculiares do PIC, tais como registradores de uso especı́fico e endereçamento indireto de memória. Os resultados esperados foram atingidos para todos os benchmarks testados e desta forma, o modelo funcional ArchC do PIC 16F84 foi validado. Os tempos de simulação dos benchmarks foram obtidos através de estatı́sticas geradas a partir do conjunto de ferramentas do pacote ArchC, que são expressos em unidades de tempo de SystemC (default time units). c) Resultados experimentais Foi realizada uma comparação do modelo do PIC 16F84 com um modelo do microcontrolador i8051, já certificado e disponı́vel no repositório do BrazilIP [Net04]. Os resultados experimentais quantitativos a seguir apresentados foram gerados usando o já citado conjunto de benchmarks do Projeto Dalton, utilizado na certificação daquele modelo. Para cada benchmark, a Tabela 3.3 compara os dois microcontroladores em termos de número de instruções executadas, tempo de simulação e tamanho de código. Note que o número de instruções executadas para o PIC é bastante menor. Isto é um indı́cio de que o compilador usado para o i8051 provavelmente tem deficiências na otimização do código. 40 Tabela 3.3: Caracterı́sticas dos benchmarks utilizados Benchmark Instruções Tempo de Tamanho de executadas simulação1 código (bytes) PIC i8051 PIC i8051 PIC i8051 negcnt 150 312 2981 6221 60 33 int2bin 256 2659 5101 53161 72 55 cast 68 995 1341 19881 120 112 divmul 296 404 5901 8061 212 190 fib 358 1218 7141 24341 140 298 sort 2227 4245 44521 84881 220 534 Os dados referentes ao tamanho de código (Tabela 3.3) são colocados em evidência na Figura 3.5. Figura 3.5: Tamanho de código: PIC 16F84 x i8051 Note que o tamanho do código gerado para o PIC é maior para a maioria dos benchmarks. Isto se deve ao fato de o PIC utilizar um formato fixo de instrução. Entretanto, os programas fib e sort apresentam um comportamento distinto, que reflete o fato de o PIC possuir recursos especı́ficos para a manipulação de vetores (estrutura de dados predominante nestes dois programas). 1 Expresso em unidade de tempo de SystemC (default time unit). 41 Deve-se fazer a ressalva de que os testes foram realizados utilizando-se compiladores comerciais de diferentes fabricantes e que, portanto, possı́veis diferenças de técnicas de otimização e geração de código podem estar embutidas nos valores medidos. A Figura 3.6 mostra os tempos de simulação2 extraı́dos da Tabela 3.3. Note que os tempos de simulação para o modelo do PIC 16F84 são menores para todos os programas testados. Por exemplo, o programa sort executou aproximadamente 2 vezes mais rápido que no i8051. No caso do programa cast, o modelo do PIC 16F84 executa aproximadamente 15 vezes mais rápido. Figura 3.6: Tempo de simulação: PIC 16F84 x i8051 Obviamente, os tempos de simulação maiores explicam-se pelo maior número de instruções executadas e, possivelmente, pela maior complexidade do conjunto de instruções (por exemplo, formato variável) do i8051. Experimentos utilizando programas mais complexos, principalmente envolvendo buffers de memória não foram realizados devido a limitações do compilador, pois seria necessário integrar ao modelo um módulo de memória externa para realizar tais experimentos. Os dados de saı́da obtidos nos experimentos com os benchmarks coincidem com os encontrados no Projeto Dalton [Pro04], justificando, desta forma, a validação do modelo funcional do PIC 16F84. 2 Expressos em unidades de tempo de SystemC (default time units). 42 Capı́tulo 4 A metodologia baseada em ADL O trabalho de pesquisa descrito nesta dissertação é parte de uma metodologia de suporte ao uso de ASIPs em SoCs. Este capı́tulo descreve as etapas da metodologia abordadas nesta dissertação, as que são abordadas em trabalhos correlatos e as que se pretende suportar em trabalhos futuros. 4.1 Visão geral da metodologia A Figura 4.1 representa esquematicamente a metodologia adotada, na qual existem 3 fluxos distintos: • Sı́ntese de HW • Co-simulação HW/SW • Sı́ntese de SW A sı́ntese de hardware inicia-se a partir de uma descrição ADL. Esta descrição é submetida a uma cadeia de ferramentas de sı́ntese que resulta em uma descrição em HDL do ASIP. Posteriormente, o hardware descrito pode ser sintetizado em uma plataforma FPGA. Este fluxo será abordado em futuros trabalhos de pesquisa. No fluxo da co-simulação hardware-software, é possı́vel gerar simuladores automaticamente a partir da descrição ADL de entrada. Este fluxo é suportado por ferramentas já disponı́veis no pacote ArchC. Já no fluxo da sı́ntese de software (foco desta dissertação), códigos-fonte escritos em C++ são compilados, gerando código assembly como saı́da. Este código é então subme43 tido ao montador para a geração de um arquivo executável, que pode ser executado no simulador ou no hardware sintetizado (por exemplo, numa plataforma FPGA). Note que o montador é parametrizável de acordo com a descrição ADL da arquitetura de um ASIP. Alterações ou extensões na arquitetura são refletidas no código executável gerado. Figura 4.1: A metodologia de projeto adotada Esta dissertação aborda parte do fluxo da sı́ntese de software mostrado na Figura 4.1, destacado pelas linhas espessas. Detalhes deste fluxo são apresentados na próxima seção. 44 4.2 Uma visão geral do montador parametrizável A Figura 4.2 expande o bloco denominado montador parametrizável na Figura 4.1, mostrando somente a parte do fluxo de sı́ntese de software abordado nesta dissertação. Figura 4.2: O montador parametrizável A descrição ADL mostrada na Figura 4.2 é o ponto de partida para o gerador de montadores e para o gerador de pré-processadores. Em particular, o gerador de préprocessadores necessita de informações sobre modos de endereçamento, macros e pseudoinstruções, todas descritas em um arquivo de configuração. O código assembly utilizado como entrada do pré-processador pode conter macros, pseudo-instruções e labels. Durante o pré-processamento, as macros são expandidas e as pseudo-instruções são substituı́das por instruções nativas. Além disso, todos os endereços simbólicos são resolvidos e substituı́dos por endereços numéricos, gerando como saı́da código assembly nativo. Este código pré-processado é submetido ao montador, cuja tarefa principal resume-se em ler cada linha do programa assembly e realizar a montagem. O código montado (executável no formato hexadecimal) pode ser executado no simulador, conforme o fluxo da co-simulação hardware-software (Figura 4.1). A geração automática de ferramentas (pré-processador e montador) ampara-se em técnicas formais baseadas em Gramática Livre de Contexto (GLC). Estas técnicas serão abordadas no Capı́tulo 5. A implementação das ferramentas de geração automática é apresentada no Capı́tulo 6. 45 Capı́tulo 5 O uso de gramáticas na geração automática de ferramentas A geração automática de ferramentas ampara-se na construção de parsers, os quais utilizam Gramáticas Livre de Contexto (GLCs) para a representação formal da sintaxe da linguagem de entrada. Este capı́tulo apresenta a definição formal de GLCs e define os principais conceitos da teoria das Linguagens Formais relacionados com gramáticas. O capı́tulo termina com a proposta de um algoritmo para a geração automática de GLCs, que é um dos elementos-chave para a geração automática de ferramentas a partir de ADLs, a ser descrita no Capı́tulo 6. 5.1 Fundamentação 5.1.1 Alfabeto (ou Vocabulário) Um Alfabeto é um conjunto finito, não vazio, de sı́mbolos (elementos), geralmente denotado por V. Exemplos: V = {a, e, i, o, u}, V = {0, 1}, etc. 5.1.2 Sentença (ou Palavra) Uma sentença sobre um alfabeto V, é uma seqüência (ou cadeia) finita de sı́mbolos do alfabeto. Exemplo de sentenças sobre V = { a , b }: a, b, aa, ab, ba, bb, aaa, ... 46 5.1.3 Fechamento (closure) de um alfabeto Seja V um alfabeto ∀. O fechamento reflexivo (ou simplesmente fechamento) de V, representado por V∗ , é dado pelo conjunto de todas as possı́veis seqüências que podem ser formadas a partir de V, inclusive a sentença vazia (). O fechamento transitivo (ou fechamento positivo) de V, representado por V+ , é dado por V∗ - {}. Exemplos: Seja V = { 0, 1 }, temos que: V∗ = {, 0, 1, 00, 01, 10, 11, 000, ...} V+ = {0, 1, 00 ,01, 10, 11, 000, ...} 5.1.4 Linguagem Uma linguagem L é um conjunto ou subconjunto das possı́veis sentenças que podem ser escritas a partir de um alfabeto. Ou seja, L ⊆ V∗ . 5.1.5 Gramática Informalmente, uma gramática pode ser definida como sendo um sistema gerador de linguagens, ou ainda, um dispositivo formal usado para especificar, de maneira finita e precisa, uma linguagem potencialmente infinita. Ou seja, uma gramática define qual subconjunto de V∗ forma uma linguagem. Segundo a hierarquia de CHOMSKY [Aea88], as gramáticas são classificadas em: • Gramática Tipo 0 (ou gramática sem restrições) • Gramática Tipo 1 (ou Gramática Sensı́vel ao Contexto - GSC) • Gramática Tipo 2 (ou Gramática Livre de Contexto - GLC) • Gramática Tipo 3 (ou Gramática Regular - GR) As linguagens geradas por GSC, GLC e GR são denominadas, respectivamente, Linguagens Sensı́veis ao Contexto (LSC), Linguagens Livres de Contexto (LLC) e Linguagens Regulares (LR). 47 5.1.6 Gramática Livre de Contexto (GLC) Dentre os quatro tipos de gramáticas de CHOMSKY, as gramáticas livre de contexto são as mais adequadas para especificação dos aspectos sintáticos de uma linguagem e constituem a base formal para a implementação de parsers. Formalmente, uma GLC é definida por G = (Vn, Vt, P, S), onde: • Vn: Conjunto finito de sı́mbolos não-terminais, os quais são utilizados na descrição da linguagem. • Vt: Conjunto finito de sı́mbolos terminais, os quais são usados na formação das sentenças da linguagem, sendo que Vn ∩ Vt = φ. • P: Conjunto finito das produções (regras gramaticais ou regras de sintaxe), onde cada produção é composta por um par (A, β), denotado por A ::= β, onde: P= {A ::= β | A ∈ Vn ∧ β ∈ (Vn ∪ Vt)∗ } • S: Pertence a Vn e é o sı́mbolo inicial da gramática, ou seja, o sı́mbolo a partir do qual as sentenças de uma linguagem são geradas. A linguagem gerada por uma GLC G = (Vn, Vt, P, S), denotada por L(G), é definida pelo conjunto de sentenças (seqüências pertencentes a Vt∗ ) que podem ser produzidas a partir do sı́mbolo inicial (S), de acordo com as regras sintáticas contidas em P. Formalmente, L(G) = {x | x ∈ Vt∗ ∧ S =⇒+ x }. Os sı́mbolos terminais (Vt) de uma gramática constituem a especificação léxica da linguagem gerada a partir dela. Esta especificação léxica pode ser representada formalmente através de diversos mecanismos, tais como autômatos finitos, gramáticas regulares e expressões regulares. A validação dos sı́mbolos terminais (tokens) é realizada por um algoritmo (programa), denominado analisador léxico, o qual pode ser gerado automaticamente a partir da especificação formal dos aspectos léxicos de uma linguagem. A validação das sentenças de uma linguagem é realizada por um algoritmo (programa), denominado analisador sintático (parser ), o qual pode ser gerado automaticamente a partir da especificação formal dos aspectos sintáticos de uma linguagem (geralmente através de GLCs). 48 5.1.7 Gramática livre de contexto LL(1) Uma gramática livre de contexto é dita LL(1) [Aea88] se, e somente se: • Não possui recursões à esquerda. • Está fatorada. • Para todo não-terminal que deriva a sentença vazia, a intersecção dos conjuntos first [Aea88] e follow [Aea88] desse não-terminal é vazia. 5.1.8 Geradores de analisadores léxico e sintático Os geradores de analisadores léxico e sintático são ferramentas que, a partir de uma especificação formal dos aspectos léxicos e sintáticos de uma linguagem, geram automaticamente os programas (reconhecedores) que efetuam a análise léxica e sintática dos programas escritos nesta linguagem. O código produzido a partir destes geradores é baseado em algoritmos (técnicas) já consolidados na literatura [Aea88]. Dentre os geradores mais conhecidos e utilizados, encontram-se o Lex (gerador de analisadores léxico) [LEX04] e o Yacc (gerador de analisadores sintático) [YAC04]. Ferramentas similares foram desenvolvidas utilizando diferentes técnicas de análise léxica e sintática e/ou visando diferentes objetivos. Entre estas estão o BISON [Com04], o GAS [GNU04] e o GALS [Ges04]. Nesta dissertação, foi adotado o GALS, um gerador de analisadores léxico e sintático desenvolvido na Universidade Federal de Santa Catarina, o qual permite a especificação unificada dos aspectos léxicos e sintáticos de uma linguagem. O GALS gera analisadores sintáticos segundo as principais técnicas de análise sintática existentes [Aea88], incluindo LALR(1) (utilizada pelo Yacc), SLR(1), LR(1) e preditiva LL(1). Uma das mais importantes caracterı́sticas do GALS é a disponibilidade de um simulador para a co-validação entre linguagem e gramática, bem como mecanismos de depuração para expressões regulares. Tais caracterı́sticas facilitam e flexibilizam a especificação léxica e sintática de uma linguagem, e conseqüentemente, a geração de seus analisadores. No GALS, a especificação léxica é baseada no formalismo de expressões regulares, conforme exemplo a seguir. A Figura 5.1 apresenta as definições regulares utilizadas na especificação dos tokens (sı́mbolos básicos da linguagem). 49 Figura 5.1: Definições regulares Na Figura 5.1, L corresponde à definição de qualquer letra maiúscula ou minúscula no intervalo de A (a) até Z (z). D define qualquer dı́gito de 0 até 9. A definição S representa o sinal positivo ou negativo que pode ser usado antes de um dı́gito (D). Em WS (white space) são definidos os sı́mbolos a ignorar, como por exemplo, espaço em branco, tabulação, final de linha e retorno. COMMENT define a formação léxica de um comentário. A Figura 5.2 exemplifica a definição de alguns tokens de acordo com a especificação da Figura 5.1. O token LABEL é formado por qualquer combinação de caracteres (exceto aqueles definidos em WS) cujo último caractere seja “:”. Um ID (identificador) deve ser formado, no mı́nimo, por uma letra (L), que pode ser seguida de outros caracteres, com as mesmas exceções descritas em LABEL. O token VALUE representa valores decimais (com ou sem sinal) ou valores no formato hexadecimal. Figura 5.2: Definição de tokens A definição :{WS}* especifica que toda a ocorrência caracteres contidos em WS (Figura 5.1) será ignorada. Já a definição :!{COMMENT} possui a funcionalidade reconhecer um comentário. Note que as duas últimas definições não possuem nome associado, o que indica que as mesmas não possuem valor sintático. Nesta seção foi exemplificado o uso do GALS para a especificação léxica de uma linguagem. No Capı́tulo 6, será exemplificada uma especificação sintática (Seção 6.1.3). 50 5.2 Vantagens do uso de GLCs A geração automática de ferramentas baseada em gramática livre de contexto traz vários benefı́cios, tais como: • Expressividade: uma GLC possui expressividade suficiente para especificação formal dos aspectos sintáticos de uma linguagem, constituindo-se, portanto, em uma base formal para a realização do processo de análise sintática. • Generalização: através de uma gramática, é possı́vel generalizar o processo de reconhecimento de programas. Por exemplo, a geração de montadores pode ser viabilizada para diferentes arquiteturas. • Robustez e corretude: nesta dissertação, em particular, a principal vantagem do uso de gramáticas é a garantia de corretude do parser gerado, possibilitando a validação de todos os programas de entrada corretamente definidos e a invalidação de todos os programas incorretos. • Flexibilidade e extensibilidade: a utilização de técnicas formais na especificação de linguagens facilita a extensão e alteração da linguagem e do parser gerado, constituindo-se um método mais rápido e seguro em relação aos métodos de extensão desprovidos de formalização. 5.3 O uso de GLC para a geração de montadores 5.3.1 Gramáticas envolvidas Na técnica de geração automática de montadores adotada nesta dissertação, duas GLCs são necessárias: • Gramática da ADL: é manualmente definida para uma dada versão da ADL. Esta GLC é submetida ao GALS para a geração automática do parser da descrição ADL. • Gramática do montador: é produzida automaticamente pelo gerador de montadores, sendo a entrada do GALS para a geração automática do parser do montador. O parser gerado está baseado nas definições léxicas e sintáticas da linguagem assembly da arquitetura descrita na ADL. 51 Na geração dos parsers é utilizada a técnica de análise sintática LL(1), a qual possibilita a análise formal, descendente e determinı́stica dos programas escritos na linguagem representada pelas gramáticas. 5.3.2 Geração automática da gramática do montador Nesta seção, apresenta-se um algoritmo para geração de uma GLC LL(1) G = (Vn, Vt, P, S), que representa a linguagem assembly da arquitetura especificada na ADL. A GLC gerada é garantidamente uma GLC LL(1), uma vez que apresenta as seguintes caracterı́sticas: • O primeiro sı́mbolo do lado direito de cada produção da gramática é sempre um sı́mbolo terminal (Vt), mais especificamente, o mnemônico da instrução. Isto implica que G não possui recursões à esquerda. • Todos os sı́mbolos terminais que iniciam as produções de G são distintos entre si, e portanto, G está fatorada. • O único sı́mbolo não-terminal da gramática gerada que deriva é o seu sı́mbolo inicial (<lista instr>), para o qual a intersecção dos conjuntos first e follow é vazia. O Algoritmo 5.1 utiliza como entrada um conjunto de estruturas de dados contendo as informações da arquitetura do conjunto de instruções da CPU descrita. Tais estruturas são construı́das por 17 ações semânticas embutidas na gramática da ADL. Um exemplo de gramática será apresentado no próximo capı́tulo (Figura 6.3). Dentre as informações presentes na estrutura de dados da entrada, o algoritmo utiliza o nome, o mnemônico e a lista de operandos (com seus separadores) de cada instrução. O algoritmo define o sı́mbolo inicial (S), os sı́mbolos não-terminais (Vn), os sı́mbolos terminais (Vt) e as regras de sintaxe (P) da gramática. Novas palavras reservadas da linguagem constituem novos sı́mbolos terminais da gramática e são definidos como um caso especial do token ID (veja a Figura 5.2). No passo 1, é realizada a inicialização dos elementos padrão da GLC, tais como sı́mbolos não-terminais, sı́mbolos terminais (tokens) e sı́mbolo inicial (com suas respectivas produções). A ação semântica #1 é utilizada no controle de labels. 52 Algoritmo 5.1 - Algoritmo de geração de GLC Objetivo: Gerar uma GLC G = {Vn, Vt, P, S} que represente a linguagem assembly da arquitetura especificada na ADL. Entrada: Estrutura de dados Lista Instruções, contendo o nome de cada instrução, seu mnemônico e uma lista operandos (com operandos e seus separadores). Saı́da: GLC G = {Vn, Vt, P, S} representando a linguagem assembly da arquitetura especificada na ADL. Método: Passo 1. Inicialização padrão dos elementos de G. Vn = {<lista instr>, <instr>} Vt = {LABEL, ID, VALUE} P = {<lista instr>::=LABEL #1 <instr> <lista instr> | <instr> <lista instr> | } S = <lista instr> Passo 2. Definição dos elementos de G dependentes da Lista Instruções. Para cada elemento da Lista Instruções faça Inı́cio Vn = Vn ∪ {<Lista Instruções.nome>} Vt = Vt ∪ {Lista Instruções.mnemônico} α = Concatena (Lista Instruções.mnemônico, “#3”) Se (Lista Instruções.lista operandos == φ) então α = Concatena (α, “#4”) Senão Para cada operando da Lista Instruções.lista operandos faça Inı́cio α = Concatena (α , Concatena (VALUE, “#2”)) Se operando for o último da Lista Instruções.lista operandos então α = Concatena (α, “#4”) Senão Inı́cio α = Concatena (α, Lista Instruções.lista operandos.separador) Vt = Vt ∪ {Lista Instruções.lista operandos.separador} Fim Fim P = P ∪ {<instr>::=<Lista Instruções.nome>, <Lista Instruções.nome>::=α} Fim 53 No passo 2, são definidos os elementos de G dependentes diretamente da descrição da arquitetura na ADL, representados pelo componente Lista Instruções. Neste passo, ocorre a geração de um sı́mbolo não-terminal para cada instrução definida na ADL, o qual passa a fazer parte do conjunto Vn. Em seguida, o mnemônico da instrução passa a ser um elemento do conjunto Vt, tornando-se uma palavra reservada da linguagem. O sı́mbolo α denota uma cadeia que estabelece a sintaxe de uma instrução. Esta cadeia é composta pelo mnemônico da instrução e, opcionalmente, por um ou mais operandos. Cada operando é representado pelo token VALUE, seguido da ação semântica #3. Nas instruções com dois ou mais operandos, os separadores destes operandos são inseridos no conjunto Vt, tornando-se sı́mbolos reservados da linguagem. Finalmente, são introduzidas novas produções em P, representando as instruções definidas na ADL. A ação semântica #2 realiza verificações nos operandos de cada instrução e a ação #3 realiza verificações sobre os mnemônicos. A ação semântica #4 finaliza o reconhecimento de uma instrução, acionando a geração de código. O epsilon () representa uma sentença vazia. Um exemplo de uma GLC gerada a partir do Algoritmo 5.1 será mostrado no próximo capı́tulo (Figura 6.2). 54 Capı́tulo 6 Geração automática de ferramentas Este capı́tulo descreve as técnicas utilizadas para implementar o montador parametrizável cuja estrutura foi apresentada no Capı́tulo 4. A Seção 6.1 aborda a geração automática de montadores, enquanto a Seção 6.2 aborda a geração automática de préprocessadores. Ao final, são apresentados os resultados dos experimentos realizados para validar e avaliar a eficiência, tanto das ferramentas geradoras quanto das geradas. 6.1 A geração automática de montadores 6.1.1 O fluxo de geração O fluxo de geração automática de um montador, mostrado na Figura 6.1, consiste das seguintes etapas: • Geração do parser da ADL • Parsing da ADL • Geração da lista de instruções • Geração da GLC para a linguagem assembly • Geração do parser do código assembly • Compilação do montador 55 Figura 6.1: O fluxo da geração de montadores O GALS [Ges04] é a chave para a geração automática do analisador léxico e sintático para a descrição ADL do conjunto de instruções, bem como para a linguagem assembly. Portanto, o GALS é utilizado na primeira e na quinta etapas. A primeira etapa é realizada pelo GALS a partir da definição da gramática da ADL, gerando automaticamente o analisador léxico e o parser da descrição ADL. Na segunda etapa é realizado o parsing da descrição ADL, o qual extrai as informações da arquitetura do conjunto de instruções e armazena-as em estruturas de dados. Na etapa seguinte, funções especializadas extraem os dados destas estruturas e geram uma lista de instruções. 56 O Algoritmo 5.1 (detalhado na Seção 5.3.2) realiza a quarta etapa, extraindo informações das estruturas de dados. Na quinta etapa, a GLC gerada pelo algoritmo é submetida ao GALS, o qual constrói automaticamente o parser da linguagem assembly representada pela gramática. Na última etapa, a lista de instruções, o analisador léxico, o parser do código assembly, algumas classes auxiliares e o analisador semântico são todos compilados, resultando na geração do montador da arquitetura especificada na descrição ADL. 6.1.2 Exemplo de geração de uma GLC As informações usadas na geração de montadores mostradas na Figura 6.1 são exibidas em nı́vel de código na Figura 6.2, a qual é estruturada da seguinte maneira: • Descrição de uma CPU (descrição ArchC) • Lista de instruções (código em C++) • GLC (notação Backus-Naur Form (BNF)) O exemplo mostrado na Figura 6.2 reflete a lista de instruções e a GLC geradas a partir da mesma descrição ArchC. Neste exemplo, a descrição é composta de único formato (Format Byte) e única instrução (ADDWF) do microcontrolador PIC 16F84. A lista de instruções é gerada a partir de funções que extraem dados das estruturas. Observe que esta lista armazena informações obtidas da ADL, tais como nome do formato (Format Byte), campos do formato (dummy, op byte, d, f), nome da instrução (ADDWF) e sintaxe assembly (ADDWF %f, %d). A gramática é gerada pela aplicação do Algoritmo 5.1 a partir dos dados obtidos da descrição ADL. A primeira linha da descrição da gramática é padrão para qualquer descrição ADL. Na segunda linha, o sı́mbolo não-terminal <ADDWF>, corresponde à instrução ADDWF definida na ADL. Na linha seguinte, observe que a produção da gramática possui um mnemônico (ADDWF), operandos (VALUE) e ações semânticas (formadas pelo par (#, número)). Note que o trecho de código mostrado na lista de instruções é código pronto para ser compilado. Já a GLC deve ser submetida ao GALS para a geração do código C++ correspondentes ao parser do montador. 57 Figura 6.2: Exemplo de geração de GLC e lista de instruções 58 6.1.3 Implementação Para o desenvolvimento do software, foi utilizada a seguinte plataforma: • Microcomputador PC • Sistema operacional Microsoft Windows • Ambiente de desenvolvimento Borland Builder • Linguagem de programação C++ O código fonte das ferramentas geradoras e geradas foi escrito em C++ padrão. Desta forma, o código é totalmente portável para o sistema operacional Linux e pode ser facilmente compilado pelo g++ da GNU [GNU04] sem necessidade de alterações. As classes geradas automaticamente são: • Lista de instruções: esta lista é gerada automaticamente pelo gerador de montadores e está armazenada no arquivo ListaInstrucoes.cpp. Na lista de instruções encontram-se todas as informações da arquitetura especificada em ArchC necessárias para geração de um montador. • Tabela de sı́mbolos: esta estrutura é gerada automaticamente pelo GALS a partir da GLC da linguagem assembly. Nesta tabela estão inseridas as informações léxicas e sintáticas extraı́das da GLC. O conteúdo da tabela de sı́mbolos é armazenado nos arquivos Constants.h e Constants.cpp. As classes construı́das manualmente são: • Classes auxiliares: estas classes possuem funções de manipulação dos dados extraı́dos da ADL e as rotinas responsáveis pela geração de arquivos contendo o códigofonte que farão parte do montador. • Analisador semântico: nestas classes estão codificadas as ações semânticas do montador. Devido a generalização das ações semânticas, um montador gerado a partir de qualquer descrição ArchC incorpora sempre um mesmo analisador semântico. Estas classes estão armazenadas nos arquivos Semantico.h e Semantico.cpp. 59 Os arquivos que contêm as rotinas e classes descritas formam o código-fonte completo do novo montador. Após a compilação destes arquivos, é gerado um montador automaticamente. Este processo é auxiliado por um script. Alguns detalhes de implementação do fluxo de geração de montadores são apresentados a seguir: a) Geração do parser da ADL: como base para a geração do parser da ADL, foi definida uma GLC com padrão BNF, a qual é apresentada na Figura 6.3. Figura 6.3: Gramática completa de uma descrição AC ISA em ArchC Nesta gramática, alguns componentes representam palavras reservadas da ADL ArchC, tais como: AC ISA, ac format, ac instr, ISA CTOR, set asm e set decoder, como exemplificado na Seção 3.3. As palavras ac addr mode A e ac addr mode R são utilizadas apenas para a geração de montadores e pré-processadores e, portanto, não fazem parte da ADL. Os sı́mbolos ID e ı̂ foram definidos no Capı́tulo 5 e os elementos ASPA, NUM, HEXA e ASSEMBLY são casos especiais de ID. Os elementos que aparecem entre os caracteres < e > representam os sı́mbolos não-terminais da gramática. Para finalizar, cada número precedido do caractere “#” representa uma ação semântica do gerador de montadores. Estas ações semânticas são utilizadas pelo GALS para a geração parcial do analisador semântico do gerador de montadores (basicamente esqueletos de classes e de funções). As ações semânticas foram implementadas manualmente. 60 b) GALS: o GALS foi usado para gerar os analisadores léxico e sintático das descrições do conjunto de instruções das arquiteturas definidas em ArchC, bem como da linguagem assembly. Um simulador disponı́vel na interface gráfica do GALS foi utilizado para testes e verificações da GLC gerada. Este ambiente permitiu simular diferentes descrições ArchC e programas assembly, subsidiando diretamente a construção dos parsers envolvidos. Com objetivo de simplificar e acelerar o processo de geração de montadores, o código fonte do GALS foi modificado. Desta forma, é possı́vel invocar o GALS através de scripts (disponı́veis para Windows/Linux) sem necessidade de utilização da sua interface gráfica, mantendo todas as verificações de inconsistências da gramática especificada. c) Estruturas de dados: as estruturas de dados disponı́veis são manipuladas pelo analisador semântico do gerador de montadores e contêm os dados definidos na ADL, tais como: • Formatos e seus respectivos campos • Instruções e sua sintaxe assembly (mnemônicos, operandos e separadores de operandos) • Definição de modos de endereçamento das instruções de desvio 6.1.4 Verificação de inconsistências Para tornar robusta a geração e o uso do montador, algumas verificações de inconsistências foram implementadas: • Verificação de sinais: esta função é realizada nos campos dos formatos declarados em ArchC pelo analisador semântico do montador, garantindo os limites mı́nimos e máximos de valores dos operandos de cada instrução de um programa assembly; • Verificação de erros léxicos, sintáticos e semânticos: qualquer erro léxico, sintático ou semântico provoca o lançamento de suas respectivas exceções, interrompendo imediatamente o processo de montagem. A não interrupção deste processo denota a correta geração de código. 61 6.2 A geração automática de pré-processadores 6.2.1 O papel do pré-processador O pré-processamento resume-se em 3 tarefas: • Substituição de palavras reservadas: os comentários são ignorados e os sı́mbolos definidos no arquivo de configuração são substituı́dos por valores numéricos. • Substituição de pseudo-instruções e macros: estes elementos são substituı́dos por instruções nativas. • Cálculo de endereços: nesta tarefa é realizada a resolução de labels, calculando seus endereços numéricos. O arquivo de saı́da do pré-processador contém somente código assembly nativo e endereços numéricos. Portanto, a função do montador resume-se apenas na montagem do código previamente processado. 6.2.2 O fluxo de geração O fluxo de geração automática de um pré-processador, mostrado na Figura 6.4 consiste das seguintes etapas: • Parsing do arquivo de configuração • Geração da classe de tratamento de labels • Compilação do pré-processador A primeira etapa a ser realizada é o parsing do arquivo de configuração, que contêm informações sobre palavras reservadas, macros, pseudo-instruções e modos de endereçamento. A estrutura do arquivo de configuração será detalhada na Seção 6.2.3. Na segunda etapa, são geradas as rotinas de resolução de labels baseadas nos modos de endereçamento descritos no arquivo de configuração. Estas rotinas são inseridas seqüencialmente em uma classe C++ que fará parte do código do pré-processador. A estrutura desta classe contendo um exemplo de rotina de resolução de labels será mostrada na Seção 6.2.3. 62 Figura 6.4: O gerador de pré-processadores O parser do pré-processador e as rotinas de manipulação de dados (por exemplo, da lista de instruções) fazem parte de um conjunto de classes denominado Classes Padrão. Além disso, o pré-processador utiliza a lista de instruções produzida pelo gerador de montadores. Portanto, a geração do pré-processador ocorrer após a geração do montador devido à dependência de dados. Na última etapa, as classes padrão, a classe de tratamento de labels e a lista de instruções são compiladas, resultando na geração de um novo pré-processador. 6.2.3 Implementação Para o desenvolvimento do gerador de pré-processadores, foi utilizada a mesma plataforma especificada na Seção 6.1.3. Esta seção fornece detalhes sobre o arquivo de configuração e a classe de resolução de labels do pré-processador. a) Arquivo de configuração: um exemplo de um arquivo de configuração do préprocessador é mostrado na Figura 6.5. 63 Figura 6.5: Definições reservadas de uma arquitetura fictı́cia A Seção AC RESERVED WORDS possui uma lista de definições padrão da arquitetura, como por exemplo, o nome de registradores e recursos da arquitetura. Nesta seção, é possı́vel declarar um sı́mbolo de comentário e sı́mbolos que devem ser ignorados pelo parser. Posteriormente, as pseudo-instruções podem ser definidas, associando-as com instruções nativas equivalentes. As macros são formadas por uma lista de instruções nativas. Peculiaridades das instruções de desvio são descritas na Seção AC ADDRESS GENERATOR, onde o endereço-alvo do desvio é representado por uma expressão aritmética. Tal expressão representa a distância (em bytes) entre a instrução de desvio e a instrução atual. A notação j: “x/4” indica que, na montagem da instrução j, o valor a ser representado em binário no campo de endereço da palavra de instrução é x/4 (ou seja, o endereço expresso em número de palavras). A informação sobre o caráter absoluto ou relativo do endereçamento não é capturada no arquivo de configuração, mas indicada na descrição ArchC através da sentença “ac addr mode A”, que denota endereçamento absoluto. b) Classe de resolução de labels: nesta classe, denominada AddressGenerator.h, é inserida uma rotina para cada expressão declarada na Seção AC ADDRESS GENERATOR (Figura 6.5). Através destas rotinas, o pré-processador calcula e substitui labels pelo seu endereço numérico efetivo. A flexibilidade da declaração destas expressões através 64 de qualquer expressão válida em C++ permite descrever facilmente os modos de desvio absoluto ou relativo existentes na arquitetura que está sendo descrita. Um exemplo da classe AddressGenerator.h, contendo a rotina correspondente à definição na Figura 6.5 é mostrada na Figura 6.6. Figura 6.6: Exemplo da classe AddressGenerator.h 6.3 Resultados experimentais Para validar e avaliar a eficiência tanto da ferramentas geradoras quanto das geradas, foram realizados experimentos conforme descrito a seguir. a) Configuração dos experimentos r Pentium Os experimentos foram realizados em um computador PC com CPU Intel 4, operando à freqüência de 1.8 GHz, com 256 MB de memória principal, sob o sistema operacional Linux Debian, com kernel versão 2.4.25-1-686. Embora as ferramentas de geração automática desenvolvidas destinem-se ao suporte de ASIPs, para fins de validação e sem perda de generalidade, foram utilizadas CPUs de propósitos gerais bem conhecidas: o MIPS e PowerPC 405. Além destes, foi utilizado o microcontrolador PIC 16F84. 65 O código produzido pelo montador gerado foi executado no modelo funcional de cada CPU-alvo, sendo que cada modelo foi gerado a partir de sua descrição ArchC. O modelo do MIPS foi obtido em [Arc04] e os modelos do PIC 16F84 e PowerPC 405 foram desenvolvidos localmente [Tea05b] [Fea04]. Os programas adotados para validar os geradores foram extraı́dos do conjunto de benchmarks do Projeto Dalton [Pro04]. Os tempos de execução, expressos em segundos, foram obtidos através do comando time do Linux, somando-se os tempos de CPU denominados user e system. A fim de gerar códigos assembly para validar os montadores gerados automaticamente, utilizaram-se os compiladores cruzados gcc [GNU04] (para o MIPS e o PowerPC) e PCW/CCS [Inc04a] (para o PIC). b) Procedimentos experimentais Para cada CPU-alvo Ci , representada através de um modelo Mi descrito em ArchC, as seguintes ferramentas foram geradas: • Um simulador do conjunto de instruções Si (gerado pelo pacote ArchC); • Um montador Ai ; • Um pré-processador Pi ; Posteriormente, cada programa benchmark foi compilado para cada CPU-alvo Ci , gerando os respectivos códigos assembly. Por sua vez, os códigos assembly de cada benchmark foram submetidos ao pré-processador Pi e ao montador Ai , resultando no código executável para a CPU-alvo Ci . c) Resultados experimentais Os resultados experimentais relativos às ferramentas geradoras são mostrados nas Tabelas 6.1 e 6.3. Os resultados experimentais referentes às ferramentas geradas são mostrados nas Tabelas 6.4 e 6.5. A Tabela 6.1 mostra os tempos1 necessários para gerar os pré-processadores e os montadores. Note que o tempo de geração do montador é dominante sobre o tempo de geração 66 do pré-processador, que pode ser desconsiderado. Como esperado, os tempos de geração são proporcionais ao tamanho do conjunto de instruções. Tabela 6.1: Tempos de geração do pré-processador e montador CPU Instruções descritas Pré-processador Montador MIPS 58 0,04 1,13 PowerPC 120 0,05 3,44 PIC 35 0,03 1,06 Para investigar a taxa de crescimento do conjunto de instruções, diferentes cores foram construı́dos, adicionando novas instruções a um subconjunto já existente, de acordo com o seguinte critério: dado um core Ci , o core Ci+1 contêm todas as instruções do core Ci adicionando-se 10 novas instruções, conforme mostra a Tabela 6.2. Tabela 6.2: Seleção de cores Core C1 ISA PowerPC 405 MIPS instruções addi, addis, bclr, bl, lbz, addi, addiu, jal, jr, lbu, 15 lwz, mfspr, or, ori, rlwinm, lui, lw, ori, sb, sll, stb, stw, stwu, cmp, cmpl srl, sw, slti, bne, j Core 1 + Core 1 + add, b, bc, subf, cmpli, sltu, addu, beq, lb, subu, sraw, divwu, mullw, sth, stbx srav, andi, sltiu, lhu, lh Core 2 + Core 2 + and, nego, mtspr, lhz, subfme, add, mult, div, mfhi, mflo, bcl, addc, mull, lhaux, divw jalr, sra, and, or, sllv Core 3 + Core 3 + addme, mcrf, nand, mulhw, oris, mthi, mtlo, sys call, break, cmpi, slw, subfe, mfcr, divwo blez, bgtz, sub, slt, xori, sh Core 4 + Core 4 + lswi, sthx, extsh, eqv, ba, multu, divu, srlv, xor, nor, subfc, lswx, mtcrf, xori, addo lwl, lwr, bltz, bgez, swl C2 C3 C4 C5 1 Número de Expressos em segundos. 67 25 35 45 55 A Tabela 6.3 mostra que o tempo2 de geração do montador cresce linearmente com o tamanho do conjunto de instruções. Tabela 6.3: Tempos de geração do montador Core Instruções descritas PowerPC MIPS C1 15 0,97 0,98 C2 25 1,00 1,01 C3 35 1,02 1,02 C4 45 1,03 1,03 C5 55 1,10 1,10 A Tabela 6.4 caracteriza os benchmarks usados nos experimentos com as ferramentas geradas. Para um dado conjunto de instruções, a coluna da esquerda representa o número de instruções executadas em cada benchmark e a coluna da direita, o tamanho do código (expresso em número de instruções). O acrônimo N/A (não aplicável) indica casos não testados. Por exemplo, o programa divmul não pôde ser testado no MIPS, pois necessita da instrução break, que não foi implementada no modelo disponı́vel em [Arc04]. O programa xram não pôde ser testado no PIC, devido a restrições do compilador utilizado. Tabela 6.4: Caracterı́sticas dos benchmarks Benchmark 2 MIPS PowerPC PIC negcnt 154 32 121 28 150 30 gcd 209 53 198 48 125 32 int2bin 153 36 143 35 256 36 cast 80 48 87 55 68 60 divmul N/A N/A 167 55 296 106 fib 490 106 445 96 358 70 sort 2982 154 2744 48 2227 110 xram 43013 42 36869 38 N/A N/A Expresso em segundos. 68 Para fins de validação, o código executável de cada benchmark foi executado em cada CPU-alvo. Os resultados experimentais foram consistentes para todos os casos testados. Com objetivo de avaliar a eficiência, os tempos de pré-processamento e montagem foram medidos, de forma conjunta, para cada benchmark, como mostra a Tabela 6.5. Tabela 6.5: Tempos de pré-processamento e montagem de cada programa Benchmark Tempo [s] MIPS PowerPC PIC negcnt 0.030 0.035 0.020 gcd 0.030 0.050 0.020 int2bin 0.040 0.040 0.030 cast 0.040 0.050 0.030 divmul N/A 0.050 0.060 fib 0.060 0.080 0.040 sort 0.070 0.110 0.050 xram 0.040 0.045 N/A A correlação dos dados das Tabelas 6.4 e 6.5 mostra que, para uma mesma CPU, o tempo cresce em menor proporção do que o número de instruções montadas. Por exemplo, no caso do MIPS, se comparados os programas negnct e sort, o número de instruções é multiplicado por 5, enquanto o tempo é multiplicado por 2,3. Este comportamento é uma evidência experimental da eficiência das técnicas propostas e ferramentas geradas. Por outro lado, para um mesmo programa benchmark testado em CPUs distintas, o tempo pode crescer em proporção maior do que o número de instruções montadas. No programa sort, por exemplo, se comparados o PIC e o PowerPC, o número de instruções é multiplicado por 1,3, enquanto o tempo é multiplicado por 2,2. Isto pode se atribuı́do à maior complexidade dos formatos de instrução do PowerPC. 69 Capı́tulo 7 Conclusões e perspectivas Esta dissertação representa uma etapa importante na implementação de uma metodologia de suporte ao uso de ASIPs em SoCs. As Seções 7.1 e 7.2 resumem os principais resultados do trabalho de pesquisa aqui descrito. A Seção 7.3 apresenta algumas perspectivas de trabalhos futuros. 7.1 Produtos de trabalho Como resultado das pesquisas no âmbito desta dissertação e em colaboração com atividades de iniciação cientı́fica [Fea04][Tea05a][Tea05b], foram desenvolvidos e validados experimentalmente um modelo e duas ferramentas: • Modelo funcional do microcontrolador PIC 16F84 • Gerador automático de montadores • Gerador automático de pré-processadores 7.2 Contribuições e discussão Esta dissertação contribui com uma nova técnica de geração automática de montadores e pré-processadores. A técnica proposta baseia-se em três elementos-chave: • Especificação unificada de aspectos léxico e sintáticos: ao contrário da ma-ioria dos trabalhos relatados na literatura [Hea97a] que se baseiam no uso do 70 Lex [LEX04] e Yacc [YAC04], a técnica aqui adotada utiliza o GALS [Ges04], um gerador de analisadores cuja entrada é uma especificação unificada de aspectos léxicosintáticos. • Novo algoritmo para geração de GLC: os trabalhos correlatos não apresentam formalmente a técnica utilizada para o processo de geração de montadores. Esta dissertação apresenta um algoritmo para geração automática de GLCs a partir de uma ADL. • Decomposição em etapas: a técnica decompõe o processo de geração e o processo de montagem em duas etapas distintas: o pré-processamento (macros, pseudoinstruções, modos de endereçamento) e a efetiva montagem de instruções nativas. Isso facilita a automação, evitando que algumas informações tenham que ser inseridas manualmente como em [Kum00]. Além disso, o tratamento das caracterı́sticas de endereçamento em nı́vel de expressão aritmética apresenta melhor usabilidade que em nı́vel de byte ou bit como em [Kum00]. A técnica proposta possui as seguintes caracterı́sticas: • Eficiência: foram apresentadas evidências experimentais da eficiência tanto das ferramentas geradoras quanto das ferramentas geradas. Os tempos de geração são suficientemente baixos e crescem linearmente com o tamanho do conjunto de instruções. Os tempos de pré-processamento e de montagem crescem linearmente com o número de instruções do programa. • Robustez e corretude: a corretude é garantida por técnicas formais baseadas em GLCs e a robustez pela adoção de uma especificação unificada de aspectos léxicosintáticos. • Manutenibilidade e extensibilidade: o formalismo baseado em GLCs torna segura a manutenção ou atualização das ferramentas em face de mudanças ou extensões na ADL. O processo de manutenção ou extensão é facilitado e acelerado através de um mecanismo de co-validação entre linguagem e gramática embutido no GALS, bem como por mecanismos de verificação de expressões regulares. 71 7.3 Trabalhos futuros Algumas alternativas de continuidade das pesquisas são mostradas a seguir: • Certificação do modelo funcional do PIC 16F84: o modelo desenvolvido será submetido ao mesmo conjunto de benchmarks usados na certificação do microcontrolador i8051, já disponı́vel no repositório do Projeto BrazilIP [Net04]. • Desenvolvimento de um modelo do PIC 16F84 com precisão de ciclos: um modelo desta natureza forneceria insumos para avaliação de desempenho e consumo de energia. • Implementação de um mecanismo de ligação: o tratamento de múltiplos arquivos com código assembly não está atualmente suportado. • Desenvolvimento de um escalonador de código: a partir de um modelo com precisão de ciclos, poder-se-ia incorporar um escalonador para pós-processar a saı́da do montador, reordenando as instruções para obter melhor desempenho do pipeline. • Redirecionamento a partir de um compilador: um tópico interessante é a adaptação do compilador da GNU/C++ para usar a descrição ADL como insumo à geração de código assembly para o montador gerado automaticamente. O escalonador de código proposto no item anterior poderia ser adaptado e incorporado, restando investigar-se como adaptar o mecanismo de seleção de instruções. 7.4 Expectativa de impacto • Insumos para trabalho correlato: É de nosso conhecimento a existência de pesquisas em andamento no Laboratório de Sistemas de Computação (LSC) da UNICAMP que visam o desenvolvimento de um gerador de montadores mais genérico para ser incorporado ao pacote ArchC. Espera-se que esta dissertação possa servir de insumo ou contraponto para tais pesquisas. • Disseminação do modelo no repositório do Projeto BrazilIP: espera-se que o modelo do PIC 16F84, subproduto desta dissertação, possa ser incorporado à plataforma Fênix e disseminado à comunidade através do Projeto BrazilIP [Net04]. 72 Referências Bibliográficas [Aea88] Alfred V. Aho and et al. Compilers: Principles, Techniques and Tools. AddisonWesley, 1988. [Aea02] Maghsoud Abbaspour and et al. Retargetable Binary Utilities. In Design Automation Conference, 2002. [Arc04] ArchC. The ArchC Architecture Description Language, 2004. http://www.archc.org. Acessado em 2004. [Bea04] Gunnar Braun and et al. A Novel Approach for Flexible and Constistent ADLDriven ASIP Design. In DAC, Jun 2004. [CF90] Peter P. K. Chiu and Sammy T. K. Fu. A Generative Approach to Universal Cross Assembler Design. SIGPLAN Notices, 25(1):43–51, 1990. [Com04] GNU Compiler. Bison Page, 2004. http://www.gnu.org/software/bison/bison.html. Acessado em 2004. [Dea01] W. J. Dally and et al. Route packets, not wires: on-chip interconnection networks. In DAC, Jun 2001. [ELF04] ELF. Executable and Linking Format, 2004. http://www.cs.ucdavis.edu/~haungs-/paper/node10.html. Acessado em 2004. [Fea04] J. O. Carlomagno Filho and et al. Geração automática de montadores a partir de ArchC: um estudo de caso com o PowerPC 405. Trabalho de Conclusão de Curso, UFSC, Dezembro 2004. [Fer66] David E. Ferguson. Evolution of the meta-assembly program. Commun. ACM, 1966. 73 [Fre93] Markus Freerick. The nML Machine Description Formalism. Technical report, TU Berlin Computer Science., Jul 1993. [Gea99] P. Grun and et al. RTGEN: An Algorithm for Automatic Generation of Reservation Tables from Architctural Descriptions. In ISSS, Jan 1999. [Gea02] Thorsten Grötker and et al. System Design with SystemC. Klumer Academic Publishers-pg 5-9, 2002. [Ges04] Carlos Eduardo Gesser. GALS- Gerador de Analisadores Léxico e Sintático, 2004. Trabalho de Conclusão de Curso - UFSC. http://gals.sourceforge.net. Acessado em 2004. [GNU04] GNU. GNU Project, 2004. http://www.gnu.org. Acessado em 2004. [Hea97a] George Hadjiyiannis and et al. An Instruction Set Description Language for Retargetability. In DAC, Jun 1997. [Hea97b] Mark R. Hartoog and et al. Generation of Software Tools from Processor Descriptions for Hardware/Software Co-design. In DAC, Jun 1997. [Hea99] A. Halambi and et al. EXPRESSION: A Language for Architecture Exploration through Compiler/Simulator Retargetability. In DATE, Mar 1999. [Inc04a] Custom Computer Service Inc. Custom Computer Service Inc. PCW/CCS, 2004. http://www.brazilip.org.br/fenix. Acessado em 2004. [Inc04b] Microchip Technology Inc. Manual do Microcontrolador PIC 16F84., 2004. http://www.microchip.com. Acessado em 2004. [Kum00] Sarika Kumari. Generation of Assemblers Using High Level Processor Models. Master’s thesis, Dept. of Computer Science and Engg., IIT Kanpur, India, Feb 2000. [LEX04] LEX and YACC. The Lex & Yacc Page., 2004. http://dinosaur.compilertools.net/. Acessado em 2004. [LIS04] LISA Project Team. Retargetable SW Development Tool Suite, 2004. http://www.ert.rwth-aachen.de/Projekte/Tools/LISA/swtools.html. Acessado em 2004. 74 [Mar03a] Grant Martin. SystemC: From Language to Applications, From Tools to Methodologies. Tutorial. SBCCI, Sep 2003. [Mar03b] Peter Marwedel. Embedded System Design. Kluwer Academic Publishers, Nov 2003. [Mea01] Prabhat Mishra and et al. Functional abstraction driven design space exploration of heterogeneous programmable architectures. In ISSS, Jan 2001. [Net04] BRAZIL-IP Network. BRAZIL-IP Network. The Fênix Platform., Nov 2004. http://www.brazilip.org.br/fenix. [Pea99] S. Pees and et al. LISA-Machine Description Language for Cycle-Accurate Models of Programmable DSP Architectures. In DAC, Jun 1999. [Pro04] Dalton Project. Synthesizable VHDL Model of 8051., 2004. http://www.cs.ucr.edu/ dalton/i8051/i8051syn/. Acessado em 2004. [Rig04] Sandro Rigo. ArchC: Uma Linguagem de Descrição de Arquiteturas. PhD thesis, Jul 2004. [Sea02] Oliver Schliebusch and et al. Architecture Implementation Using the Machine Description Language LISA. In DAC, Jun 2002. [Sys04] SystemC. SystemC Community, 2004. http://www.systemc.org. Acessado em 2004. [Tea05a] Leonardo Taglietti and et al. Geração Automática de Ferramentas para ASIPs a partir de Linguagem de Descrição de Arquiteturas. Submetido ao Iberchip Workshop. 2005. [Tea05b] Leonardo Taglietti and et al. Modelagem do microcontrolador PIC 16F84 para projeto baseado no reuso de IPs. Submetido ao Iberchip Workshop. 2005. [Tra87] William J. Tracz. Advances in Microcode Support Software. In Annual Workshop on Microprogramming, 1987. [Wea87] H. Wu and et al. GPASM: A General Purpose Cross Assembler for Microprocessors. In IEEE Asian Eletronics Conference, 1987. 75 [Wic75] John Dryer Wick. Automatic Generation of Assemblers. PhD thesis, December 1975. [Wol00] Wayne Wolf. Computers as Components. Morgan Kaufmann Publishers, 2000. [YAC04] YACC. YACC - Yet Another Compiler Compiler. Gerador de Analisadores Sintáticos, 2004. http://www.ma.adfa.oz.au/Local/Info/bison/bison toc.html. Acessado em 2004. 76