Computador Acadêmico Básico Reconfigurável Por: Sílvio Fernandes e Leonardo Casillo Processador Simples A Figura 1 mostra um sistema digital que contem vários registradores de 32 bits (um deles, o R12, além de registrador também é um contador – usado para prover o endereço de memória de onde as instruções são lidas, comumente chamado de program counter (PC)), um multiplexador (multiplexers), uma ULA – Unidade Lógica e Aritmética (ALU), e uma unidade de controle (control unit). A entrada de dados desse sistema é feita via entrada DIN de 32 bits, que se comunica com a memória externa. Os dados podem ser carregados através do multiplexador, de 32 bits de largura, para vários registradores da arquitetura, tais como R0, ..., R12, A, G, DOUT, ADDR. Os endereços dos registradores de uso geral são mostrados na Tabela 1. A saída do multiplexador é chamada de barramento (bus) na figura pois esse termo é geralmente usado para os sinais que permitem transferir os dados de um sistema para outro. Bus 32 Incr_PC ... R0 R12 (PC) Mask A ... DIN ALU MUX G ADDR 32 IR 3 R12_In MUX R0_In 3 4 32 SEL DOUT G_In A_In ... Z,S,Cy DOUT_In ADDR_In Control Unit RUN RESET W R DONE Figura 1 - Esquema do processador simples Tabela 1. Registradores de uso geral REGISTRADOR R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 (PC) ENDEREÇO (Bin) 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 ENDEREÇO (Hexa) 0 1 2 3 4 5 6 7 8 9 A B C A ULA é responsável por operações lógicas e/ou aritméticas: soma, subtração, E lógico, OU lógico, NÃO lógico, transparência e deslocamento de acordo com a Tabela 2. Tabela 2 - Operações da ULA SINAL PARA ULA OPERAÇÃO 000 soma 001 subtração 010 and 011 or 100 not A 101 transparência 110 deslocamento para direita 111 deslocamento para esquerda Isso é determinado para a ULA através do sinal Alu após a decodificação da instrução pela unidade do controle. A ULA utiliza os dados vindos do barramento diretamente ou indiretamente (do registrador A). A quantidade de dado depende do tipo de instrução. Por exemplo, a instrução que realiza a soma de dois termos, o primeiro dado vem do barramento e é armazenado no registrador A e o segundo dado vem do barramento direto para a ULA. O resultado da operação é armazenado no registrador G. O dado em G pode ser transferido para um dos outros registradores caso seja necessário. A ULA ainda possui flags que indicam se o resultado da operação resultou em zero (Z), se resultou em um número negativo (S) e se houve uma propagação de carry (CY). Os dados podem ser transferidos de um registrador para outro através do multiplexador. Esse multiplexador recebe um sinais de 4 bits (Mux) que seleciona quais das entradas é passada para a saída do multiplexador (barramento). O valor do sinal de seleção do multiplexador e a entrada correspondente transmitida para o barramento é mostrada na Tabela 3. Tabela 3 - Seleção do Multiplexador Seleção do Multiplexador 0000 0001 ... 1100 1101 1110 1111 Valor na saída do multiplexador R0 R1 ... R12 Mask G DIN O sistema pode executar diferentes operações a cada ciclo, controladas pela unidade de controle (control unit). Essa unidade determina quando um dado em particular é colocado no barramento e qual registrador deve carregá-lo. Por exemplo, se a unidade de controle coloca Mux em “0000” e liga o Ain então o multiplexador transmitirá o conteúdo de R0 para o barramento e esse dado será carregado na próxima subida do clock no registrador A. Este sistema executa as instruções mostrada na Tabela 4. As 2 primeiras colunas mostram o código da operação (codop), em binário e em hexadecimal respectivamente, a terceira coluna mostra o nome da instrução e seus operandos e a última coluna o significado. A sintaxe RX ← [RY] significa que o conteúdo do registrador RY é carregado no registrador RX. A instrução mv (move) permite que o dado de um registrador possa ser copiado para outro. Para a instrução mvi (move immediate) a expressão RX ← #D indica que um valor constante D de 32 bits é carregado no registrador RX. A instrução ld (load) carrega um dado para o registrador RX a partir do endereço da memória externa especificado no RY. A instrução st (store) armazena o dado contido no registrador RX no endereço de memória encontrado no RY. A instrução mvnz (move if not zero) permite uma operação de mv ser executada apenas sob a condição do conteúdo atual do registrador G não ser igual a zero. Tabela 4 – Operações realizadas pelo processador Código da Operação (Bin) 00000000 00000001 00000010 00000011 00000100 00000101 00000110 00000111 00001000 00001001 00001010 00001011 00001100 00001101 Código da Operação (Hexa) 0 1 2 3 4 5 6 7 8 9 A B C D Operação mv Rx, Ry mvi Rx, #D mvnz Rx, Ry add Rx, Ry sub Rx, Ry and Rx, Ry or Rx, Ry not Rx ld Rx, [Ry] st Rx, [Ry] ldi Rx jmp #D jnz #D shl Rx, Ry Função Executada Rx ← [Ry] Rx ← D IF G != 0, Rx ← Ry Rx ← [Rx] + [Ry] Rx ← [Rx] – [Ry] Rx ← [Rx] and [Ry] Rx ← [Rx] or [Ry] Rx ← not[Rx] Rx ← [[Ry]] [Ry] ← [Rx] G ← Rx PC ← D IF G != 0, PC ← D Rx ← [Ry] << 1 00001110 00001111 00010000 00010001 00010010 00010011 00011111 00010100 a 00011110 1111xxxx E F 10 11 12 13 1F 14 a 1E --- shr Rx, Ry jnc #D jns #D jz #D jc #D js #D halt Reservado Rx ← [Ry] >> 1 IF Cy != 0, PC ← D IF S != 0, PC ← D IF Z = 0, PC ← D IF Cy = 0, PC ← D IF S = 0, PC ← D PC ← PC --- Configuráveis ??? As instruções e dados são transferidas de/para a memória através da entrada DIN. A comunicação entre o processador e a memória é feita passando o endereço (ADDR) e/ou dado (DOUT) para a memória. A saída W do processador, quando ativa, indica escrita do dado DOUT no endereço ADDR. A saída R do processador, quando ativa, indica leitura do dado no endereço ADDR. A Figura 2 representa essa comunicação. ADDR Read_Address Saída Write_Address W Write R Read DIN Memory DOUT Data Clock Figura 2 - Comunicação processador/memória Cada instrução pode ser codificada e armazenada no registrador IR usando formato de 32 bits IIIIIIIIXXXXYYYYZZZZZZZZZZZZZZZZ, onde IIIIIIII (8 bits) representa o código da instrução (codop), XXXX (4 bits) o registrador RX, YYYY (8 bits) o registrador RY e ZZZZZZZZZZZZZZZZ (16 bits) pode representar o valor constante. Caso a instrução utilize como operandos 2 registradores, então os bits ZZZZZZZZZZZZZZZZ (16 bits) não são usados, podem ser deixados em zero. Quando a instrução utiliza apenas 1 registrador, como na instrução mvi, os bits YYYY não tem significado, o valor da constante #D ocupa os outros 16 bits na palavra da instrução, representado por ZZZZZZZZZZZZZZZZ. Esse valor é enviado para o barramento através do multiplexador por meio da saída Mask, cujo valor é (em hexadecimal) “0000DDDD”. Nas instruções jmp e jnz os bits XXXX e YYYY e os outros 16 bits na palavra da instrução correspondem ao endereço do salto da instrução que será enviado para o PC. A instrução especial HALT indica o fim do programa, então o processador ficará parado aguardando um sinal de RESET. Algumas instruções, como adição e subtração, levam mais que um ciclo de clock para ser completada, por causa de várias transferências de dados através do barramento. A unidade de controle deve implementar uma máquina de estados, onde a ordem dos estados é determinada por cada instrução, ou seja, é o passo-a-passo da instrução. O processador começa executando a instrução na entrada DIN quando o sinal Run é acionado e o processador liga o sinal Done quando a instrução é finalizada. A Tabela 5 indica os sinais de controle que devem ser ligados em cada passo para implementar as instruções da Tabela 4. Perceba que no passo 0 de cada instrução, apenas o sinal de controle IRin é ligado (para receber a instrução). Tabela 5 - Sinais do controle ligados em cada instrução/tempo T0 (mv): IRin (mvi): IRin (mvnz): IRin (add): IRin T1 Mux=RY, RXin, Done Mux=Mask, RXin, Done Se !Z=> Mux=RY, Gin Senão => Done Mux=RX, Ain (sub): IRin T2 T3 Mux=G, RXin, Done Mux=RY, Alu=add, Gin Mux=G, RXin, Done Mux=RX, Ain Mux=RY, Alu=sub, Gin Mux=G, RXin, Done (and): IRin Mux=RX, Ain Mux=RY, Alu=and, Gin Mux=G, RXin, Done (or): IRin Mux=RX, Ain Mux=RY, Alu=or, Gin Mux=G, RXin, Done Mux=RX, Alu=not, Gin Mux=G, RXin, Done (ld): IRin Mux=RY, ADDRin Mux=DIN, RXin, Done (st): IRin Mux=RX, DOUTin Mux=RY, ADDRin, W_D, Done (not): IRin (ldi): IRin (shl): IRin Mux=RX, Alu=transp, Gin, Done Mux=Mask, R12in, Done Se !Z=> Mux=Mask, R12in, Done Senão => Done Mux=Ry, Alu=shl, Gin Mux=G, RXin, Done (shr): IRin Mux=Ry, Alu=shr, Gin (jmp): IRin (jnz): IRin Mux=G, RXin, Done O registrador R12 é o contador de programa (PC), o qual provê o endereço de memória de onde as instruções são lidas. Quando o Reseten é ativado o PC é colocado em zero. No início de cada instrução (T0) o conteúdo de PC é usado como endereço de uma instrução que está na memória. A instrução é armazenada em IR e o PC é automaticamente incrementado para o ponto da próxima instrução (no caso da instrução mvi o PC prove o endereço do dado imediato e é então incrementado novamente). A unidade de controle utiliza o sinal incr_PC para indicar o incremento de PC, o qual apenas habilita esse contador. Também é possível carregar diretamente um endereço dentro de PC (R12) usando mv ou mvi tendo como destino o registrador R12. Um exemplo de código que usa PC para implementar um loop é mostrado a seguir, onde o texto depois de % em cada linha é apenas um comentário. A instrução mv R2,R12 move para R2 o endereço de memória da instrução sub R1,R0. Então, a instrução mvnz R12,R2 provoca a execução da instrução sub repetidamente até que R1 se torne zero. mvi R0,#1 mvi R1,#10000000 mv R2,R12 sub R1,R0 mvnz R12,R2 % binary delay value % save address of next instruction % decrement delay count % continue subtracting until delay count gets to 0 Reconfiguração de instruções: Para configurar os estados de uma instrução é necessário configurar os 26 bits de controle do datapath do processador conforme a seqüência abaixo. ULA 3 R0in ... R12in 13 Mux 4 IR 1 A 1 G 1 Dout 1 Addr 1 wd 1 end 1 Todos os codops que possuem seus 8 bits iniciais iguais a „1‟ foram reservados para executar instruções reconfiguradas (16 instruções ao todo). Ao decodificar o codop da instrução atual, a unidade de controle deverá identificar se este é utilizado para executar uma instrução presente no processador, ou se irá buscá-la na memória em um endereço específico para cada instrução reconfigurável. Os codops reconfiguráveis devem Para diminuir a complexidade da configuração de instruções, a quantidade de estados suportados por cada instrução foi limitada a 6. Com isso, é possível buscar cada instrução reconfigurada, sabendo-se exatamente qual seu endereço inicial e a quantidade total de estados utilizados. Isto evita que a unidade de reconfiguração necessite alterar a tabela dinamicamente a cada vez que uma instrução é inserida ou removida. Para inserir o programa contendo as instruções e os estados de cada instrução, deve-se utilizar uma memória RAM, do tipo LPMRAM, de 32 bits de palavra, disponível na biblioteca de componentes da ferramenta Quartus II, da Altera. Sugere-se utilizar uma memória de 216 ou 232 endereços. As instruções reconfiguradas serão inseridas no processador juntamente com o restante do programa de execução. A memória deverá receber um arquivo .mif (Memory Initialization File), que contém as instruções, dados e estados de configuração utilizados no programa. As instruções de como utilizar um arquivo .mif podem ser encontradas no help do Quartus II. Deve-se definir no .mif 3 áreas distintas: uma área de instruções, uma área de dados e uma área de estados de configuração. As duas primeiras serão definidas de acordo com o tamanho da LPM_RAM criada. A terceira área deverá ter no mínimo 96 palavras (6 estados para cada uma das 16 instruções). Ao decodificar uma instrução reconfigurada, a unidade de controle precisa saber qual o endereço do primeiro estado de cada instrução. Desse modo, a unidade de controle deverá conter uma tabela com os respectivos endereços de busca para cada codop. Exemplo: o codop 1111111100000000 (X”FF00”) poderá ser associado ao endereço de memória X”E000”. O codop X”FF01” associado ao endereço X”E006”, e assim sucessivamente. Caso a instrução não ocupe os 6 estados disponíveis, deve-se obrigatoriamente setar o bit end da palavra de estado de configuração, que indica ao processador que a instrução reconfigurável está concluída. Ao executar uma instrução reconfigurada, cada vez que ocorre a busca de um estado, deve-se verificar o valor do bit end. Se positivo, a instrução é terminada. Senão, verifica-se se foi atingido o limite de 6 estados. Quando o limite for atendido, identificar o final da instrução. Interface com a placa DE2. - Utilização de 1 led (LEDG8) para indicar o fim da execução de 1 instrução. - Utilização de 1 led (LEDR0) para indicar o fim da execução da instrução HALT, ou seja, o fim do programa. - Utilização de 2 botões: 1 para a função RESET (botão KEY3) e 1 para a função RUN (botão KEY2). - Utilização de 8 displays de 7 segmentos para exibir (em hexadecimal) o conteúdo de partes do processador. - Uso das chaves (SW0 a SW4) para selecionar qual parte deve ser exibido no display de 7 segmentos. A Tabela 6 abaixo exibe as possíveis seleções. Tabela 6. Chaves DE2 para selecionar o que será exigido no disply 7 segmentos Chave 00000 00001 00010 00011 00100 00101 00110 00111 01000 01001 01010 01011 01100 01101 01111 10000 10101 10110 Outros Valor Exibido R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 Barramento A G Saída do Mux Saída da ULA X"FFFFFFFF" A Figura 3 representa o mecanismo de seleção através das chaves (SW0 a SW4) para exibição dos conteúdos no display 7-segmengos. MUX 32 Chaves da DE2 Barramento Saída da ULA ... Saída do Mux R12 G ... A R0 56 Decoder: 7-Segmentos FFFFFFFF Figura 3. Interface Display de 7 Segmentos Programando No momento da compilação do código VHDL, um arquivo no formato .mif inicializa a memória do processador com o programa que será executado. Desse modo, a cada novo programa o projeto deve ser recompilado junto com o novo programa. Também há uma restrição com relação ao nome do arquivo com o programa que inicializará a memória, o qual deve está com o nome “programa.mif” para seja carregado corretamente na memória. Como ilustração vejamos um pequeno exemplo, que carrega um valor do endereço #9 da memória e faz um laço de repetição até atingir o valor que foi carregado. (1) mvi r5,#9 //armazena #9 em R5 (será endereço de memória) (2) mvi r4,#1 //armazena #1 em R4 (3) ld r6,r5 //carrega da memória o valor do endereço em R5 e armazena em R6 (4) sub r6,r4 //subtrai valor de R6 por R4 e armazena em R6 (5) jnz #4 //se o resultado da subtração não for zero pula para endereço 4 (6) halt //fim de programa Para que esse programa seja executado no processador antes é necessário criar seu código objeto equivalente e salvá-lo como “programa.mif”. Para cada instrução temos que escrever um código no formato (IIIIIIIIXXXXYYYYZZZZZZZZZZZZZZZZ) apresentado no início desse texto. Então para a primeira instrução (mvi r5,#9) temos o codop ou IIIIIIII como 0x01 (utilizamos “0x” para indicar que estamos escrevendo um valor em hexadecimal). Para indicar o registrador R5 (XXXX) temos o código 0x5. Como essa instrução não utiliza um 2º. registrador então o valor YYYY fica em zero 0x0. E o valor constante do campo ZZZZZZZZZZZZZZZZ fica com 0x0009. O resumo dessa instrução e das demais desse exemplo são apresentadas na Tabela 7. Código objeto para o exemplo do laço, com os valores em hexadecimal. Tabela 7. Código objeto para o exemplo do laço Instrução mnemônica mvi r5,#9 mvi r4,#1 ld r6,r5 sub r6,r4 jnz #4 halt Codop (IIIIIIII) 01 01 08 04 0C 1F RX (XXXX) 5 4 6 6 0 RY (YYYY) 0 0 5 4 0 #D 0009 0001 0000 0000 000004 0000 Código objeto 01500009 01400001 08650000 04640000 0C000004 1F000000 Agora vejamos um exemplo com um pouco mais de complexidade: um fatorial. O algoritmo é apresentado a seguir. Algoritmo Fatorial: Início: Leia Acc; A <= 1; B <= 1; C <= 1; Acc <= Acc - C; Se Acc = 0 Então vá para Fim; Fim Se; Loop: B <= B + C; A <= A * B; Acc <= Acc - C; Se Acc != 0 Então vá para Loop; Fim Se; Fim: Acc <= A; (01) (02) (03) (04) (05) (06) (07) (08) (09) (10) (11) A implementação desse algoritmo utilizando o conjunto de instruções do processador, considerando: R0 = Acc R1 = A R2 = B R3 = C R4 = 1 R5 = 0 (0) mvi R11, End(FAT) (1) ld R0, R11 (2) mvi R1, #1 (3) mvi R2, #1 (4) mvi R3, #1 (5) mvi R4, #1 (6) mvi R5, #0 (7) sub R0, R3 (Acc = Acc – C) (8) jz #19 (Se Acc = 0 goto 19) (9) add R2, R3 (B = B + C) (10) mv R6, R1 (rotina para multiplicação) (11) mv R7, R2 (12) sub R7, 1 (B = B – 1) (13) jz PC #16 (Se B = 0, goto 16 ) (14) add R6, R1 (A = A + A) (15) jmp PC#12 (va para 12) (16) mv R1, R6 (17) sub R0, R3 (Acc = Acc – C) (18) jnz PC, #9 (Se Acc != 0 goto 9) (19) mv R0, R1 (Acc = A) (20) halt O código objeto equivalente para o exemplo do fatorial é o seguinte: (0) mvi R11, End(FAT) (1) ld R0, R11 (2) mvi R1, #1 (3) mvi R2, #1 (4) mvi R3, #1 (5) mvi R4, #1 (6) mvi R5, #0 (7) sub R0, R3 (8) jz #19 (9) add R2, R3 (10) mv R6, R1 (11) mv R7, R2 (12) sub R7, R4 (13) jz #16 (14) add R6, R1 (15) jmp #12 (16) mv R6, R1 (17) sub R0, R3 (18) jnz PC #9 (19) mv R0, R1 (20) halt 01B00020 080B0000 01100001 01200001 01300001 01400001 01500000 04030000 11000013 03230000 00610000 00720000 04740000 11000010 03610000 0B00000C 00160000 04030000 0C000009 00010000 1F000000 O formato do arquivo .mif possui um cabeçalho que informa a largura das palavras da memória (WIDTH) e a quantidade de palavras (DEPTH), qual a base (ex: HEX para hexadecimal) de representação dos endereços (ADDRESS_RADIX) e dos dados (DATA_RADIX). Em seguida o conteúdo da memória deve está entre os marcadores “CONTENT BEGIN” e “END;”. Cada palavra da memória é representada pelo endereço (na base indicada antes) seguida por dois pontos e o valor (na base indicada antes) terminado com um ponto-e-vígula. Para o exemplo do laço de repetição o arquivo no formato .mif é mostrado a seguir. WIDTH=32; DEPTH=8192; ADDRESS_RADIX=HEX; DATA_RADIX=HEX; CONTENT BEGIN 0000 : 0B000001; 0001 : 0150000A; 0002 : 01600001; 0003 : 00000000; 0004 : 04560000; 0005 : 0C000004; 0006 : 1F000000; [0007 .. 1FFF] : 00000000; END; Referências ALTERA. Altera Tutorials and Lab Exercises. Disponível em: http://www.altera.com/education/univ/materials/manual/unv-lab-manual.html. Acessado em: set. de 2008. ALTERA. DE2 Development and Education Board. Disponível em: http://www.altera.com/education/univ/materials/boards/unv-de2-board.html. Acessado em: set. de 2008.