FE310G: Um microcontrolador open source - Interrupções no RISC-V - Embarcados
Neste segundo artigo sobre o RISC-V eu falo um pouco sobre o sistema de interrupções e de processamento de exceção do RISC-V e sobre a primeira implementação em silício do RISC-V, o FE310G da SiFive. Para mais informações sobre as instruções e registradores do RISC-V, sugiro a leitura da primeira parte deste artigo FE310G: Um microcontrolador open source – Estrutura básica do RISC-V.
EIP (UEIP, SEIP e MEIP): flag de interrupção externa pendente (oriunda do PLIC). A habilitação desta fonte de interrupção é feita através do registrador MIE (bits UEIE, SEIE e MEIE).
O mecanismo de interrupção do PLIC é completado por um elemento chave que é o registrador localizado no endereço 0x0C200004 (claim/complete): este registrador sinaliza o ID atual da interrupção em tratamento pelo software (ou zero se não houver interrupção em tratamento). O código da ISR deve fazer o "claim" ou reivindicação da interrupção, sinalizando ao PLIC que irá tratar a interrupção indicada. O processo de reivindicação ocorre simplesmente pela leitura do registrador. O PLIC então irá promover o apagamento do flag de interrupção pendente correspondente ao ID reivindicado.
set_csr(mie, MIP_MTIP); // habilita interrupção do timer no modo máquina
set_csr(mstatus, MSTATUS_MIE); // habilita interrupções globais
O FE310G é a primeira implementação comercial em silício de um RISC-V e inclui um core de 32 bits seguindo a ISA RV32IMAC, que consiste no conjunto completo de instruções de 32 bits, além de instruções comprimidas (com tamanho reduzido para 16 bits), multiplicação e divisão por hardware e operações atômicas. O core E31 utilizado no chip inclui também um pipeline de 5 estágios, sistema de predição de desvios com tabela de 40 entradas para endereços de destino, 128 entradas de histórico de desvio e pilha de dois níveis para endereços de retorno. Este sistema de predição de desvios evita o esvaziamento do pipeline (e eventualmente do cache) em razão de desvios no fluxo do código. Caso a predição de desvio falhe, a instrução de desvio é executada em três ciclos de clock (ao invés de um). A maioria das instruções é executada em 1 ciclo de clock (desde que esteja dentro do cache), mas instruções de carga (load) como LW (load word) é executada em 2 ciclos enquanto que LB, LBU, LH, LHU (carga de byte ou half-word) são executadas em 3 ciclos, instruções de leitura de CSR executam em 5 ciclos, multiplicações executam em 5 ciclos e divisões entre 2 e 33 ciclos (conforme os operandos).