UNIVERSIDADE FEDERAL DE SANTA CATARINA DEPARTAMENTO DE INFORMÁTICA E ESTATÍSTICA CURSO DE CIÊNCIAS DA COMPUTAÇÃO Rafael Vargas Implementação de um soft-core em VHDL baseado no conjunto de instruções MIPS-I Prof. Dr. Antônio Augusto Fröhlich Orientador Florianópolis, agosto de 2006. Objetivo O objetivo principal é desenvolver um soft-core implementando um subconjunto do conjunto de instruções MIPS-I [1]. Bem como os dispositivos periféricos necessários para o acesso à memória e as operações de Entrada e Saída. Este soft-core tem como objetivo final ser sintetizado em uma plataforma FPGA como a Xilinx Multimedia FPGA Platform [2], juntamente com a aplicação e os demais componentes periféricos. Este trabalho tem como metas específicas: - Possibilitar que o código que será rodado no soft-core seja gerado pelo GCC; Criar um sistema de Entrada e Saída completo, mapeado em memória e com interrupções. Características do Projeto Arquitetura do conjunto de instruções O conjunto de instruções MIPS-I foi escolhido por ser um conjunto de formato fixo (32 bits), simples e bem conhecido, o que facilita a sua implementação. Sendo que também é possível, no futuro, adicionar novas instruções, uma vez que existem também os conjuntos de instruções subseqüentes dos quais MIPS-I acaba sendo um subconjunto. As instruções implementadas podem ser divididas em três grupos: Load e Store, Lógicoaritmética e Jump e Branch. Os formatos de instruções e sua codificação podem ser vistos no Apêndice A. Estrutura do Processador Figura 1: Estrutura da CPU A figura 1 mostra a estrutura do processador, que será composto por um IP (do inglês Intellectual Property) Mapeador de memória que será encarregado de mapear os endereços de memória para os seus dispositivos correspondentes, como por exemplo, o intervalo de endereços 0x10010000 até 0x1001FFFF, que pertence à área de dados, definindo assim intervalo de 64 Kbytes. Isto possibilita que apesar de conceitualmente, de acordo com a arquitetura Harvard, serem dispositivos separados, ambos os dispositivos de memória estejam no mesmo dispositivo físico, de acordo com a arquitetura de Von Neumann. Também compõem o soft-core o núcleo de execução que e uma UART (do inglês Universal Asynchronous Receiver-Transmitter), cuja função é executar as operações de entrada e saída. Núcleo de Execução O núcleo de execução, que como previamente dito, implementa um subconjunto do conjunto de instruções MIPS-I, é o coração do soft-core. Composto por 32 registradores de 32 bits cada. Este é o IP encarregado de executar as instruções contidas na memória de instruções e a partir destas controlar o mapeador de memória para ler ou escrever na memória de dados ou utilizar a UART como saída. Registradores Nome Número Uso Constante zero Dado temporário do montador (Assembler) Valores para retorno de função e avaliação de expressões $a0-$a3 $4-$7 Parâmetros de funções $t0-$t7 $8-$15 Temporários $s0-$s7 $16-$23 Temporários salvos $t8-$t9 $24-$25 Temporários $k0-$k1 $26-$27 Reservado para o kernel do SO $gp $28 Global pointer $sp $29 Stack pointer $fp $30 Frame pointer $ra $31 Endereço de retorno Tabela 1: Registradores da CPU $zero $0 $at $1 $v0-$v1 $2-$3 Preservado após uma chamada? N/A não não não não sim não não sim sim sim não Como demonstrado pela tabela 1, a CPU é composta por 32 registradores, sendo um deles contendo a constante zero (0) e os demais 31 são de uso geral. Há, porém, uma convenção para a utilização destes registradores. De acordo com esta convenção, os registradores marcados como “Preservado após uma chamada”, mantém seu valor, mesmo após uma chamada normal de função (utilizando a instrução jal) esta convenção diz que o registrador $at é reservado para utilização pelo montador (Assembler) como para o armazenamento temporário de constantes ou a execução de pseudo-instruções. Os registradores $v0 e $v1 devem ser utilizados para, ao final da execução de uma função, armazenar os valores de retorno, como um endereço para um array e seu tamanho. Por sua vez, do registrador $a0 ao $a3, devem ser armazenados os parâmetros que serão passados à função que será chamada. Existem também dez registradores para uso geral ($t0,$t1, ...,$t9). Há ainda, oito outros registradores para uso geral ($s0-$s7). Há também dois registradores reservados para uso do kernel do SO ($k0 e $k1); além dos registradores para o Global Pointer ($gp), Stack Pointer ($sp) e Frame Pointer ($fp); e um registrador destinado a conter o endereço da próxima instrução a ser executada quando a função que está executando no momento terminar. Figura 2: Datapath do núcleo de execução (atualizar imagem) De acordo com Patterson e Hennessy [4], a execução da instrução se dá por meio dos seguintes passos e ações. Cada instrução necessita de três a cinco destes passos: 1. Busca da instrução: Busca a instrução da memória, apontada por PC, e calcula o endereço da próxima instrução somando quatro ao valor atual de PC. 2. Decodificação da instrução e busca dos registradores: São lidos os registradores identificados por rs e rt (e gravados em registradores temorários A e B, respectivamente), supondo que a instrução seja do tipo R, pois caso não seja, os valores desnecessários podem ser simplesmente descartados. Também é calculado o possível valor da próxima instrução, caso esta seja um branch, que também pode ser ignorado caso não seja. 3. Execução, computação do endereço de memória, ou término do branch: Neste passo a ALU (do inglês Arithmetic and Logic Unit) executa uma, de quatro funções, dependendo do tipo da instrução, podendo esta função ser: • Endereço de memória: O resultado será A somado do valor do campo “imediato” com o sinal extendido para 32 bits. • Cálculo lógico-aritmético: O resultado será A (operação) B, onde (operação) pode ser qualquer operação da ALU. • Branch: Subtrai B de A, e caso o valor seja igual a zero (valores iguais) atualiza o valor de PC para o endereço calculado no ciclo anterior. • Jump: Concatena os 3 bits de mais alta ordem do PC com os 26 bits de mais baixa ordem da instrução deslocados 2 bits para a esquerda. E o valor resultante é escrito em PC. 4. Acesso à memória ou término de instrução lógico-aritmética: No caso de acesso á memória o endereço é determinado pela saída da ALU no ciclo anterior. Para leitura, o valor lido é salvo para o próximo ciclo, e para gravação, é gravado o dado de B. Já no caso de instrução lógico-aritmética (tipo R) o registrador identificado por rd é escrito com o valor da saída da ALU no ciclo anterior. 5. Término de leitura de memória: Aqui, o valor lido da memória no ciclo anterior é escrito no registrador identificado por rd. Memória Será utilizado um modelo flat de memória, dispensando assim a utilização de uma complexa unidade de gerenciamento de memória (MMU, Memory Management Unit). Haverá, porém, uma unidade de mapeamento de memória, cuja função será mapear as leituras e escritas dos endereços “virtuais” para os endereços “físicos” dos dispositivos periféricos ao núcleo de execução, como memória (tanto de dados como de instruções) e UART. UART Este é o dispositivo encarregado pela parte de entrada e saída do processador, que foi implementado para estabelecer um meio de comunicação com o meio externo ao softcore, utilizando uma interface RS-232. Características da implementação Linguagem VHDL VHDL, do inglês Very-High-Speed Integrated Circuit Hardware Description Language é uma linguagem de descrição de hardware originalmente desenvolvida para documentar o comportamento de ASICs. Posteriormente foram criadas ferramentas simuladoras e sintetizadoras que poderiam ler o VHDL e ter como saída uma definição de uma implementação física de um circuito [5]. Existem também outras linguagens para descrição de hardware como Varilog, porém o VHDL tem vantagens como o fato de ser uma linguagem fortemente tipada. Polpeta [3] diz que em Verilog não há o conceito de pacotes, assim como não existem diretivas para a configuração ou replicação de estruturas e o recurso de parametrização é muito pobre, sendo assim, necessário sobrescrever constantes ao longo do processo de síntese para que, deste modo, os componentes sejam pré-processados corretamente. Referências [01] MIPS Instruction Set. http://techpubs.sgi.com/library/manuals/2000/007-2597001/pdf/007-2597-001.pdf [02] http://www.xilinx.com/products/boards/multimedia/ [03] Polpeta, Fauze V. Uma Estratégia para a Geração de Sistemas Embutidos baseada na Metodologia Projeto de Sistemas Orientados à Aplicação. Dissertação de mestrado, UFSC. 2006. [04] Patterson, A. e Hennessy, J. L. Computer Organization and Design. Morgan Kaufmann Publishers. 2nd Ed. 1997. Apêndice A Formatos das instruções do MIPS-I. São três os formatos de instruções: o do tipo R, de registradores; do tipo I, de imediato; e do tipo J, de jump. Nome Campos Tamanho do campo 6 bits 5 bits 5 bits 5 bits 5 bits 6 bits Formato R op rs rt rd sa funct Formato I op rs rt imediato Formato J op endereço op rs rt rd sa funct imediato endereço opcode source register target register destination register shift amount function Comentário 32 bits por instrução Instrução aritmética Branch ou imediato Jump código da instrução registrador fonte registrador fonte no formato R e destino no formato I registrador destino quantificador de deslocamento define a função que será utilizada para instruções cujo código é SPECIAL. valor imediato com sinal usado para: operadores lógicos, operadores aritméticos com sinal, deslocamento de endereço em load/store, deslocamento de instruções relativo ao PC. endereço que será deslocado 2 bits à esquerda para suprir os 28 bits de endereço da instrução jump. [CONTINUAR ESPECIFICAÇÃO DA LINGUAGEM DE MONTAGEM]