nanoFOX - um kernel simples compatível com RISC-V

Uma pequena introdução:


A idéia de escrever seu próprio núcleo surgiu após a aprovação de um seminário escolar sobre circuitos digitais na cidade de Tomsk . Nesse evento, foi feita uma introdução às linguagens atuais de descrição de hardware (Verilog HDL e VHDL), bem como ao pequeno núcleo do processador schoolMIPS . Para entender a estrutura dos núcleos, decidiu-se inventar sua própria bicicleta, seguindo o caminho de desenvolvimento do schoolMIPS, mas usando outro sistema de comando como base. Devido à crescente popularidade do RISC-V e à abertura do seu sistema de comando (o MIPS não tinha um sistema de comando aberto no momento em que o kernel foi gravado), um conjunto de instruções do RISC-V, ou seja, RV32I, foi escolhido para o desenvolvimento do futuro kernel. O RV32I possui um pequeno conjunto de instruções básicas (37 excluindo as especiais) e pode ser expandido, se desejado, por exemplo, adicionando instruções de multiplicação e divisão inteiras (RV32M) ou suporte para instruções reduzidas (RV32C). Além disso, este projeto foi concebido como educacional, por isso foi decidido maximizar a visibilidade do kernel para demonstrar efetivamente seu trabalho.


Por analogia com o schoolMIPS, as seguintes versões do kernel foram implementadas:


  1. Versão de ciclo único (00_simple_risc_v_cpu).
  2. Uma versão de ciclo único com suporte para instruções lw / sw (carregar palavra / armazenar palavra) (01_simple_risc_v_cpu_lwsw).
  3. Versão do pipeline (transportador de 5 estágios) (02_pipe_risc_v_cpu).

Atualmente, a próxima versão do kernel é descrita (03_pipe_risc_v_cpu_fc) com um conjunto completo de comandos RV32I (sem levar em consideração alguns especiais).


Breve informação:


No decorrer da descrição do kernel, foram pensadas maneiras de melhorar a visibilidade do trabalho, depuração e verificação. Atualmente implementados os seguintes métodos:


  1. Adicionando um módulo VGA de texto de depuração (para duas ramificações de kernel de ciclo único). A inclusão deste módulo permite rastrear simultaneamente o valor de 32 registros na tela do monitor, o que não é possível ao usar a saída de informações em indicadores de sete segmentos. Nas figuras apresentadas abaixo, o kernel calcula os números de Leonardo e exibe informações no módulo de depuração correspondente;


    hex_display e DebugScreenCore

    Saída de informações em indicadores de sete segmentos: imagem
    Saída de informações no visor VGA: imagem


  2. Adicionando mensagens ao terminal do simulador sobre o status do arquivo de registro e executando atualmente as instruções. Este método permite analisar melhor a operação do kernel nos estágios iniciais de desenvolvimento, mas nem sempre é conveniente;


    Terminal

    Inicialização do arquivo de registro: imagem
    Alterar valor de sp: imagem


  3. Adicionando variáveis ​​de string à forma de onda com a exibição de instruções executáveis. Usando essas variáveis ​​de cadeia, o desenvolvedor pode rastrear a configuração correta dos sinais de controle em todos os estágios do pipeline;


    Forma de onda

    Inicialização do arquivo de registro: imagem
    Alterar valor de sp: imagem


  4. Adicionando a capacidade de gravar informações de depuração sobre o estado do kernel em um arquivo de texto. O status do arquivo de registro é apresentado em forma de tabela e as instruções / instruções atualmente executadas pelo kernel também são indicadas. É um análogo de 2 pontos, mas permite mais manipulações com as informações recebidas;


    Arquivo de texto

    Inicialização do arquivo de registro: imagem
    Alterar valor de sp: imagem


  5. Adicionando a capacidade de gravar informações de depuração sobre o estado do kernel em um arquivo HTML. O status do arquivo de registro é apresentado em forma de tabela com notas sobre a alteração dos valores das células, bem como as instruções atualmente sendo executadas pelo kernel. É um análogo dos parágrafos 2 e 4, mas, além deles, permite indicar convenientemente uma alteração nos dados. Como pode ser visto nas figuras abaixo, se o valor do registro não foi definido, os registros são destacados em vermelho (registros s0 / fp - t6). No ciclo 17, o valor do registro s0 / fp muda e a célula é destacada em verde.
    No ciclo 41, o valor 0x00010000 é carregado no registro sp.


    Arquivo HTML

    Inicialização do arquivo de registro: imagem
    Alterar valor de sp: imagem



Comparação de ramificações do kernel:

Instruções de kernel atualmente suportadas para diferentes ramificações:


Manual de instruções00_simple_risc_v_cpu01_simple_risc_v_cpu_lwsw02_pipe_risc_v_cpu
adicionar+++
e--+
sll--+
ou+++
addi+++
ori--+
slli+++
lw-++
jalr--+
lui+++
beq+++
bne--+
sw-++
jal--+
sub++-

Periféricos suportados:


Periféricos00_simple_risc_v_cpu01_simple_risc_v_cpu_lwsw02_pipe_risc_v_cpu
RAM-++
Pwm-++
GPIO-++
UART--+

Idiomas suportados para escrever programas:


Linguagem00_simple_risc_v_cpu01_simple_risc_v_cpu_lwsw02_pipe_risc_v_cpu
Montador+++
C--+

Recursos FPGA necessários para o kernel (nf_cpu):


EP4CE22F17C6 (de0_nano):


01_simple_risc_v_cpu_lwsw02_pipe_risc_v_cpu03_pipe_risc_v_cpu_fc
Total de bits de memória0 / 608.256 (0%)2.048 / 608.256 (<1%)2.144 / 608.256 (<1%)
Elementos lógicos totais3.645 / 22.320 (16%)1.739 / 22.320 (8%)2.058 / 22.320 (9%)
Total de funções combinacionais2,665 / 22,320 (12%)1.472 / 22.320 (7%)1.838 / 22.320 (8%)
Registradores lógicos dedicados1.055 / 22.320 (5%)575 / 22.320 (3%)606 / 22.320 (3%)

10M50DAF484C7G (de10_lite):


00_simple_risc_v_cpu01_simple_risc_v_cpu_lwsw02_pipe_risc_v_cpu03_pipe_risc_v_cpu_fc
Total de bits de memória0 / 1.677.312 (0%)0 / 1.677.312 (0%)2.048 / 1.677.312 (<1%)2.144 / 1.677.312 (<1%)
Elementos lógicos totais2.851 / 49.760 (6%)2.881 / 49.760 (6%)1.629 / 49.760 (3%)1.927 / 49.760 (4%)
Total de funções combinacionais2.613 / 49.760 (5%)2,665 / 49,760 (5%)1.473 / 49.760 (3%)1.849 / 49.760 (4%)
Registradores lógicos dedicados1.055 / 49.760 (2%)1.055 / 49.760 (2%)575 / 49.760 (1%)606 / 49.760 (1%)

Desenvolvimento de projetos.


O que está planejado para ser feito no futuro:


  1. adicione todas as instruções do RV32I (no estágio de descrição);
  2. implementar depuração;
  3. adicione um controlador DMA (DMA);
  4. adicione suporte para outros pneus AXI, Avalon, Wishbone;
  5. adicionar memória cache (cache);
  6. integrar vários periféricos (SPI, TWI (I2C), Ethernet (10 base-t));
  7. adicionar controlador de interrupção;
  8. portar versões diferentes para outras placas de depuração;
  9. adicione outros métodos para aumentar a visibilidade do kernel;
  10. executando o RTOS, por exemplo, zephyr .

Recomendações e sugestões para o desenvolvimento do núcleo também são aceitas.


Link para o repositório: nanoFOX .

Source: https://habr.com/ru/post/pt451388/


All Articles