Merry Quartusel, ou como o processador ganhou vida



Ao depurar programas regulares, os pontos de interrupção podem ser definidos em quase todos os lugares e em quantidades razoavelmente grandes. Infelizmente. Quando um programa é executado no controlador, esta regra não se aplica. Se houver uma seção na qual o diagrama de tempo é formado, a parada irá estragar tudo. E a passagem em frequências baixas e altas não é a mesma coisa. As condições de contorno são um flagelo dos desenvolvedores. Ou, digamos, um barramento USB. No NIOS II, não trabalhei com ele, mas no STM32 é terrível. E eu quero ver alguma coisa, e quando você para, você pega um tempo limite. Em geral, com muita frequência, apesar da presença de depuração avançada do JTAG, o comportamento do programa em áreas de tempo crítico é obscurecido. Seria ótimo ver, pelo menos após a execução, por qual cadeia o programa passou, quais ramificações funcionaram e quais não!

É ainda mais importante conhecer o histórico de exceções. No NIOS II, eu não fiz isso, mas no Cyclone V SoC no núcleo do ARM - completamente. Ao depurar, tudo funciona e, se você iniciar o programa a partir da ROM, receberá uma exceção. Está claro como eles entraram e que tipo de desenvolvimento da situação levou a isso não é. O rastreamento também quebra todas as capas.

Artigos anteriores da série:
  1. Desenvolvimento do “firmware” mais simples para FPGAs instalados no Redd e depuração usando o teste de memória como exemplo
  2. Desenvolvimento do “firmware” mais simples para FPGAs instalados em Redd. Parte 2. Código do Programa
  3. Desenvolvimento de núcleo próprio para incorporação em um sistema de processador baseado em FPGA
  4. Desenvolvimento de programas para o processador central Redd no exemplo de acesso ao FPGA
  5. As primeiras experiências usando o protocolo de streaming no exemplo de comunicação de CPU e processador no FPGA Redd

1. Introdução


É costume escrever artigos educacionais com uma expressão séria, apresentando o material com calma e imparcialidade. Mas, infelizmente, isso nem sempre funciona. Agora, de acordo com o plano, deve haver um artigo sobre a otimização do processador sintetizado no complexo Redd, no qual precisamos falar sobre os recursos de trabalhar com o cache. A seguir, é apresentado um artigo sobre atrasos no acesso ao barramento. Em geral, tudo isso pode ser mostrado em um osciloscópio. Eu já fiz isso em um artigo sobre DMA (" DMA: Mitos e Realidade "). Mas eu queria demonstrar tudo usando o próprio processador, realizei essas verificações no núcleo do ARM no FPGA Cyclone V SoC. Muito conveniente (embora os resultados não tenham sido publicados). Por esse motivo, decidi lidar com o mecanismo de rastreamento inerente ao bloco JTAG. É uma pena que, até agora, eu não tenha sido capaz de exibir com meios gratuitos para download quantas batidas esse ou aquele comando foi executado, mas havia material através do qual o programa sempre pode ser perguntado como chegou a essa vida. Bem, além do mais, enquanto as lembranças das noites tempestuosas ainda estiverem frescas em minha memória, eu as expulsarei de uma maneira bastante emocional. Portanto, hoje haverá muitas memórias e um pouco de teoria útil.

Hardware


Portanto, muitas vezes ao depurar um programa para um microcontrolador, é desejável conhecer o caminho que ele percorreu e deve transmiti-lo a toda velocidade. Para o caso do NIOS II, esse mecanismo está disponível e está incluído aqui nesta guia das propriedades do núcleo do processador:



Tipo de rastreamento define o tipo de informação a ser armazenada. Você não pode salvar nada (isso salvará a memória do chip), você pode salvar apenas o histórico de comandos (na maioria das vezes isso é suficiente), ou salvar o histórico de comandos e dados. Vale ressaltar que a documentação diz que, no último modo, salvar informações é algo difícil, enquanto sobreposições com o histórico de comandos são possíveis e mais memória é consumida. Portanto, use este modo apenas quando for realmente necessário.

O parâmetro Trace Storage define o tipo de memória na qual o rastreamento será salvo. A documentação diz que a memória externa não é suportada pelo ambiente de desenvolvimento padrão. Portanto, é melhor escolher apenas o interior.



Bem, Onchip Trace Frame Size define o tamanho do buffer. Quanto maior o buffer, mais eventos podem ser colocados nele, maior o histórico pode ser considerado. Mas menos será a memória do cristal para outras necessidades.



Não há necessidade de ativar a caixa de seleção criando uma porta JTAG separada. Deixe tudo táxis em um regular.

Suporte de software


Bom Então montamos o núcleo do processador, o que vem depois? Ohhhh! Então a história do detetive começa. Se as figuras acima devem ser interpretadas como um guia de ação, seguirão as ilustrações que mostram uma bagunça e engasgos. Vários documentos dizem que, para trabalhar com o rastreamento, você deve usar programas caros de terceiros e até equipamentos JTAG especiais. Mas em alguns documentos, escapa-se que você pode levar algo em tempo integral.

Experiências Eclipse


Ótimo. Vamos dar uma olhada no Eclipse. Lembro que eu uso o ambiente de desenvolvimento Quartus Prime 17.1. Bem, aconteceu. Iniciamos o programa para depuração e vamos para o item de menu que permite abrir várias janelas:



Lá, selecionamos a janela Debug-> Trace Control:



E nós temos um boneco:



Mas a sessão de depuração é iniciada. Além disso, os itens de menu Iniciar rastreamento e Parar rastreamento até apareceram nele (antes de abrir essa janela, eles não estavam). Mas eles estão bloqueados. E não pude ativá-los.



Em vão, preenchi o Google com pedidos diferentes. Nos documentos antigos, esses itens são descritos como funcionando muito bem, mas nos modernos eles simplesmente não são mencionados. Ninguém os menciona nos fóruns. Talvez alguém nos comentários lhe diga uma coisa?

Problemas com a versão mais recente do Eclipse


Bom E a versão mais recente do ambiente de desenvolvimento? Talvez tudo funcione lá? Yyyyyy! Este é um tópico para um capítulo separado. A versão mais recente para o quarto e quinto ciclones é 18.1.1. Ou seja, você deve primeiro baixar a versão 18.1 e instalar a atualização 18.1.1. Se alguém decidiu que eu tenho muito tempo livre, que reorganizo o software para o bem de tudo, então está tudo bem. A verificação principal era sobre problemas de cache. Eles são mais sérios, eu queria dar uma olhada na nova versão, só não estou escrevendo sobre eles aqui.

Então, eu baixei. Instalado. Em primeiro lugar, a versão 18.1 no WIN7 é lançada, mas a 18.1.1 não encontra a DLL. Bom Descobri que preciso baixar o Redist do Visual Studio 2015. Instalei-o. Começou a correr. Criou um projeto com um sistema de processador. Ele até ficou pronto. Vou para o Eclipse, criando um programa com BSP baseado nele, tudo, como já fizemos várias vezes ... E eu entendo esse tipo de coisa ...



O projeto não está indo. Se você sair e entrar, ele será aberto apenas parcialmente.



Veja a pasta fechada? Lá vai você. Porque Ohhhh! Três arquivos têm:



Estes são os maravilhosos atributos de proteção:



Portanto, eles não podem ser abertos ou alterados ... Se você der mais direitos, o projeto será aberto, mas os arquivos não serão completamente criados, portanto, não funcionará para coletá-lo. Tentei dar direitos até o Eclipse ser fechado e salve o projeto. O resultado é o mesmo.

O Windows 7, que está envelhecendo rapidamente, pode ser o culpado? Não é de admirar que eu não tenha bibliotecas! Coloquei o Quartus fresco no WIN10, obtive um resultado completamente idêntico ao criar o projeto! Eu tenho um amigo Em virtude de seu local de trabalho, ele às vezes encontra produtos de fabricantes nacionais. E ele expressa uma série de pensamentos sobre si mesmos e sobre seus parentes. Bem, sobre o fato de "quem está construindo isso?" Sabe, olhando para a diversão no software Intel, começo a pensar que é longe do país de origem ... Na verdade, esse não era o caso de Alter ... Tudo aconteceu, mas não me lembro disso.

Acabei de sair. Copiei o projeto para uma unidade flash USB com o sistema de arquivos FAT32. Não há atributos de segurança. Abri o projeto, entrei no Eclipse e criei o código. Sem atributos de segurança - sem problemas. Depois copiei de volta para o disco rígido e ... Bem, é claro, tive problemas para gerar BSP. Porque o arquivo * .bsp contém muitos caminhos relativos e um absoluto. É bom que eu peguei um pen drive. Caso contrário, eu não teria notado que o BSP cai nele (já que este é o berço do projeto), e o projeto é coletado no disco rígido. Aqui está um exemplo desse caminho (já corrigido):



Bem, tudo bem ... Tudo foi gerado, montado ... E funciona exatamente da mesma forma que na versão 17.1 ... E para controladores SoC no novo ambiente, você também precisa recriar a cadeia JTAG todas as vezes no programador. Na versão 17.1, bastava fazer isso uma vez e salvar ... Eeeeeh. Bem, oh, bem ...

Altera Monitor e seu problema


De uma forma ou de outra, as pesquisas na rede pelas palavras Iniciar rastreamento e Parar rastreamento me levaram a documentos interessantes. Eles descrevem várias versões de um programa engraçado chamado Altera Monitor hoje (o nome era diferente em documentos antigos). Encontrá-la era relativamente fácil. Você precisa fazer o download do pacote do Programa Universitário para sua versão do ambiente de desenvolvimento. Preste atenção às restrições de licença. Mas, como estamos estudando agora, não temos medo disso. Mas para o trabalho comercial - tudo está ruim lá. Detalhes aqui: www.intel.com/content/www/us/en/programmable/support/training/university/materials-software.html

Baixar, colocar ... Há um documento anexado à versão atual (porque as versões espalhadas na Internet variam muito). Eu até tentei executar um exemplo para minha placa de ensaio DE0-Nano-SoC. Ele está trabalhando Mas quando tentei fazer meu projeto, ele não funcionou. O arquivo * .sof é carregado no FPGA, após o qual, após algum tempo, uma mensagem é exibida:



Somente não há informações na janela especificada. Se você tentar fazer o download novamente: bem, o texto aparecerá exatamente nessa janela:
Não foi possível consultar os IDs da instância JTAG.

Verifique se o FPGA foi configurado usando o arquivo .sof correto.

Que tipo de problema é esse? Eu pesquisei no Google. Encontrados vários fóruns com o mesmo problema. Em um momento, um funcionário da Intel perguntou com que frequência o autor tinha no JTAG e sugeriu definir um padrão. Embora, naquela época, eu já entendesse que não era uma questão de frequência: o exemplo corporativo funcionou e como defini-lo? Em um fórum, o autor escreveu que de alguma forma havia passado. Ele não entendeu como. E ele disse que se você fizer tudo cuidadosamente, de acordo com as instruções, tudo funcionará. O resto da imagem era o mesmo. O homem pergunta. Eles não respondem a ele. Depois de seis meses ou um ano, alguém escreve que ele tem a mesma situação, houve uma solução? E silêncio aaaaaaaa ...

Tentativas de solução experientes


Bom Qual poderia ser o motivo? No começo, decidi dar uma olhada em um exemplo de trabalho. Que tipo de misterioso JTAG ID? Isso pode ser devido à presença de um sistema de identificação do sistema em funcionamento?



Adicionado a si mesmo, não ajudou. Talvez o JTAG para a ponte Avalon, ao qual todos os dispositivos periféricos estejam conectados adicionalmente, seja o culpado?



Adicionado - não ajudou. Tentei mais algumas hipóteses, mas percebi que você pode adivinhar para sempre. Com pesar, eu até perguntei a Yandex, Bing e até BaiDu. Todos eles sabem menos que o Google. Ficou claro que tivemos que lidar com a descompilação para extrair do próprio programa o que era necessário. Verificado em que idioma o programa está escrito. Aconteceu isso em Java. O bytecode é armazenado no arquivo Altera_Monitor_Program.jar. Bem, é estranho. Exceto pelo fato de eu não conhecer esse Java. No Java Script, houve um caso, envolvido na Internet das Coisas, mas não encontrei um Java real. Mas onde o nosso não desapareceu!

Análise de bytecode JAVA para encontrar o problema


Como abrir código de bytes? O Google levou a um artigo sobre Habré, que afirma que, para isso, você precisa usar a JD-GUI. Encontrei no github, baixei. Identifiquei a área do problema rapidamente, pois a JD-GUI possui uma navegação interativa maravilhosa. Deixei o post no site em 10 minutos. Esta seção chama um programa de terceiros, após o qual analisa sua resposta. A chamada é assim:
systemConsoleCommand[index] = "system-console"; systemConsoleCommand[var24++] = "--script=" + Globals.gHost.getMonitorProgramRootDir("bin/jtag_instance_check.tcl", true); systemConsoleCommand[var24++] = cable; systemConsoleCommand[var24++] = Globals.gProject.system.sofFilename; try { Process sysConsoleProc = NiosIIShell.executeCommand(systemConsoleCommand).start(); BufferedReader gdbIn = new BufferedReader(new InputStreamReader(sysConsoleProc.getInputStream())); 

Bem, e além disso - análise da resposta que ainda não consideramos.

Com esse código, tentei abrir o console do NIOS II:



Lá fui para o diretório onde está o arquivo sof e dirigi a linha de comando:
system-console --script = jtag_instance_check.tcl USB-0 test.sof

No entanto, para isso, tive que copiar o arquivo C: \ intelFPGALite \ 17.1 \ University_Program \ Monitor_Program \ bin \ jtag_instance_check.tcl no mesmo local em que está o sof, para não sofrer com o caminho. No final, recebi uma resposta bastante decente:

TYPE_NAME altera_avalon_jtag_uart.jtag FULL_HPATH jtag_uart_0 (INSTANCE_ID: 0)

TYPE_NAME altera_nios2_gen2.data_master FULL_HPATH nios2_gen2_0 (INSTANCE_ID: 0)


Tudo parece lindo ...

Rastreio de Bytecode JAVA


Se o caso ocorreu hoje, esta seção não existiria. Mas aconteceu ontem. Eu ainda entendia Java muito mal. O que foi escrito lá enquanto analisava o texto era uma floresta escura para mim. É verdade que, por dois anos, meu filho participou de cursos de programação olímpica em 1 franqueados soviéticos (certificados e folhetos eram 1 soviético). Dinheiro louco foi dado para esses cursos. E eles os ensinaram lá apenas em Java. Portanto, ele também não entendeu o que foi escrito mais adiante no código (mantendo a intriga, publicarei o código um pouco mais baixo, não agora). Em geral, havia um sentimento persistente de que era hora de rastrear. Eu conheço a seção ruim, vejo que as linhas foram recebidas lá e o programa não gosta delas com alguma coisa. E daí?

A criança me encontrou um artigo maravilhoso: www.crowdstrike.com/blog/native-java-bytecode-debugging-without-source-code

Ele fala sobre um plugin muito útil para o Eclipse, que permite trabalhar com JARs, definindo pontos de interrupção neles. Onde baixar, encontrei aqui: marketplace.eclipse.org/content/bytecode-visualizer/help

Baixei o Eclipse, baixei o plug-in para instalação offline com tristeza ao meio ... Comecei a instalar - não há bibliotecas suficientes. Comecei a ler. Acontece que existem três versões do plugin. Sob Eslipse 4.5 (Marte), 4.4 (Luna) e 4.3 (não lembro o nome). Bem, tudo é simples. Vamos ao site do Eclipse, vemos um link para baixar a versão do Mars para Java ... E ... Está morto. Isso não importa! Existem cerca de uma dúzia de espelhos! .. E todos os links para eles estão mortos. Tentamos o Luna para Java, há links para x64 mortos, para x86 há um vivo ... Como um amigo meu diz: "Hemorróidas, é abrangente." Em geral, o Google teve dificuldade, mas me encontrou um assembly Java de 64 bits da versão Mars em algum servidor não oficial. Eu baixei por meia hora, mas baixei.

Implementou um plugin, criou um projeto ... Horror! Lá, o rastreio não está no nível do código-fonte, mas no nível de um assembler. Em resumo, o código de bytes decodificado é rastreado. Mas, na verdade, isso não importa! Afinal, você sempre pode verificar com as fontes descompiladas abertas em outra janela, além de que o plug-in mostra comentários muito bons ... Também se descobriu que os pontos de interrupção podem ser definidos não em nenhum lugar, mas apenas na entrada da função. Mas não consigo parar! Não há muito lá e você precisa caminhar da entrada para a área problemática.

Deixe-me lembrá-lo de que as linhas processadas são assim:
TYPE_NAME altera_avalon_jtag_uart.jtag FULL_HPATH jtag_uart_0 (INSTANCE_ID: 0)

TYPE_NAME altera_nios2_gen2.data_master FULL_HPATH nios2_gen2_0 (INSTANCE_ID: 0)

E aqui está o código Java:
 if (str.contains("(INSTANCE_ID:")) { Pattern getInstance = Pattern.compile("\\(INSTANCE_ID:(\\d+)\\)"); Matcher idMatcher = getInstance.matcher(str); if (idMatcher.find()) { String foundstr = idMatcher.group(1); instance = Integer.parseInt(foundstr); } 

isola perfeitamente o ID da instância. E aqui está o código:
  Pattern getHPath = Pattern.compile("FULL_HPATH (.+?)\\|(.+?) \\("); Matcher hpathMatcher = getHPath.matcher(str); if (hpathMatcher.find()) { hpath = hpathMatcher.group(2).replace("|", "."); } 

A variável hpath não é preenchida. Hoje eu já sei que a expressão regular:
 "FULL_HPATH (.+?)\\|(.+?) \\(" 

requer duas palavras separadas por uma barra vertical. Bem, então apenas o que é depois da linha é tomada. Eu não sabia ontem. Mais interessante é outro. A criança estudou trabalhar em Java por dois anos e não aprendeu expressões regulares! Não, é claro que eles aprenderam não a linguagem, mas a programação da Olimpíada por meio da linguagem, mas, pelo que entendi, as expressões regulares em Java estão na ordem das coisas. Eles aceitam esse dinheiro, sacam certificados de empresas conceituadas, mas não ensinam coisas importantes ... Mas eu discordo.

Luz no fim do túnel


Qual é a linha vertical? Pegamos o projeto que funcionou, damos a mesma equipe e obtemos esta resposta:

TYPE_NAME altera_avalon_jtag_uart.jtag FULL_HPATH Computer_System: The_System | JTAG_UART (INSTANCE_ID: 0)

TYPE_NAME altera_avalon_jtag_uart.jtag FULL_HPATH Computer_System: The_System | JTAG_UART_2nd_Core (INSTANCE_ID: 1)

TYPE_NAME altera_avalon_jtag_uart.jtag FULL_HPATH Computer_System: The_System | JTAG_UART_for_ARM_0 (INSTANCE_ID: 2)

TYPE_NAME altera_avalon_jtag_uart.jtag FULL_HPATH Computer_System: The_System | JTAG_UART_for_ARM_1 (INSTANCE_ID: 3)

TYPE_NAME altera_nios2_gen2.data_master FULL_HPATH Computer_System: The_System | Nios2 (INSTANCE_ID: 0)

TYPE_NAME altera_nios2_gen2.data_master FULL_HPATH Computer_System: The_System | Nios2_2nd_Core (INSTANCE_ID: 1)

O que é o Computer_System: The_System? Tudo é simples aqui. Nesta série de artigos, estou promovendo uma ideia avançada em que o sistema de computadores está no nível superior da hierarquia.
E este exemplo tem esta camada Verilog:
 module DE0_Nano_SoC_Computer ( //////////////////////////////////// // FPGA Pins //////////////////////////////////// // Clock pins input CLOCK_50, input CLOCK2_50, input CLOCK3_50, // ADC output ADC_CONVST, output ADC_SCLK, output ADC_SDI, input ADC_SDO, // ARDUINO inout [15:0] ARDUINO_IO, inout ARDUINO_RESET_N, // GPIO inout [35:0] GPIO_0, inout [35:0] GPIO_1, // KEY input [1:0] KEY, // LED output [7:0] LED, // SW input [3:0] SW, //////////////////////////////////// // HPS Pins //////////////////////////////////// // DDR3 SDRAM output [14:0] HPS_DDR3_ADDR, output [2:0] HPS_DDR3_BA, output HPS_DDR3_CAS_N, output HPS_DDR3_CKE, output HPS_DDR3_CK_N, output HPS_DDR3_CK_P, output HPS_DDR3_CS_N, output [3:0] HPS_DDR3_DM, inout [31:0] HPS_DDR3_DQ, inout [3:0] HPS_DDR3_DQS_N, inout [3:0] HPS_DDR3_DQS_P, output HPS_DDR3_ODT, output HPS_DDR3_RAS_N, output HPS_DDR3_RESET_N, input HPS_DDR3_RZQ, output HPS_DDR3_WE_N, // Ethernet output HPS_ENET_GTX_CLK, inout HPS_ENET_INT_N, output HPS_ENET_MDC, inout HPS_ENET_MDIO, input HPS_ENET_RX_CLK, input [3:0] HPS_ENET_RX_DATA, input HPS_ENET_RX_DV, output [3:0] HPS_ENET_TX_DATA, output HPS_ENET_TX_EN, // Accelerometer inout HPS_GSENSOR_INT, // I2C inout HPS_I2C0_SCLK, inout HPS_I2C0_SDAT, inout HPS_I2C1_SCLK, inout HPS_I2C1_SDAT, // Pushbutton inout HPS_KEY, // LED inout HPS_LED, // LTC inout HPS_LTC_GPIO, // SD Card output HPS_SD_CLK, inout HPS_SD_CMD, inout [3:0] HPS_SD_DATA, // SPI output HPS_SPIM_CLK, input HPS_SPIM_MISO, output HPS_SPIM_MOSI, inout HPS_SPIM_SS, // UART input HPS_UART_RX, output HPS_UART_TX, // USB inout HPS_CONV_USB_N, input HPS_USB_CLKOUT, inout [7:0] HPS_USB_DATA, input HPS_USB_DIR, input HPS_USB_NXT, output HPS_USB_STP ); //======================================================= // REG/WIRE declarations //======================================================= wire hps_fpga_reset_n; //======================================================= // Structural coding //======================================================= Computer_System The_System ( //////////////////////////////////// // FPGA Side //////////////////////////////////// // Global signals .system_pll_ref_clk_clk (CLOCK_50), .system_pll_ref_reset_reset (1'b0), // ADC .adc_sclk (ADC_SCLK), .adc_cs_n (ADC_CONVST), .adc_dout (ADC_SDO), .adc_din (ADC_SDI), // Arduino GPIO .arduino_gpio_export (ARDUINO_IO), // Arduino Reset_n .arduino_reset_n_export (ARDUINO_RESET_N), // Slider Switches .slider_switches_export (SW), // Pushbuttons .pushbuttons_export (~KEY), // Expansion JP1 .expansion_jp1_export ({GPIO_0[35:19], GPIO_0[17], GPIO_0[15:3], GPIO_0[1]}), // Expansion JP7 .expansion_jp7_export ({GPIO_1[35:19], GPIO_1[17], GPIO_1[15:3], GPIO_1[1]}), // LEDs .leds_export (LED), //////////////////////////////////// // HPS Side //////////////////////////////////// // DDR3 SDRAM .memory_mem_a (HPS_DDR3_ADDR), .memory_mem_ba (HPS_DDR3_BA), .memory_mem_ck (HPS_DDR3_CK_P), .memory_mem_ck_n (HPS_DDR3_CK_N), .memory_mem_cke (HPS_DDR3_CKE), .memory_mem_cs_n (HPS_DDR3_CS_N), .memory_mem_ras_n (HPS_DDR3_RAS_N), .memory_mem_cas_n (HPS_DDR3_CAS_N), .memory_mem_we_n (HPS_DDR3_WE_N), .memory_mem_reset_n (HPS_DDR3_RESET_N), .memory_mem_dq (HPS_DDR3_DQ), .memory_mem_dqs (HPS_DDR3_DQS_P), .memory_mem_dqs_n (HPS_DDR3_DQS_N), .memory_mem_odt (HPS_DDR3_ODT), .memory_mem_dm (HPS_DDR3_DM), .memory_oct_rzqin (HPS_DDR3_RZQ), // Accelerometer .hps_io_hps_io_gpio_inst_GPIO61 (HPS_GSENSOR_INT), // Ethernet .hps_io_hps_io_gpio_inst_GPIO35 (HPS_ENET_INT_N), .hps_io_hps_io_emac1_inst_TX_CLK (HPS_ENET_GTX_CLK), .hps_io_hps_io_emac1_inst_TXD0 (HPS_ENET_TX_DATA[0]), .hps_io_hps_io_emac1_inst_TXD1 (HPS_ENET_TX_DATA[1]), .hps_io_hps_io_emac1_inst_TXD2 (HPS_ENET_TX_DATA[2]), .hps_io_hps_io_emac1_inst_TXD3 (HPS_ENET_TX_DATA[3]), .hps_io_hps_io_emac1_inst_RXD0 (HPS_ENET_RX_DATA[0]), .hps_io_hps_io_emac1_inst_MDIO (HPS_ENET_MDIO), .hps_io_hps_io_emac1_inst_MDC (HPS_ENET_MDC), .hps_io_hps_io_emac1_inst_RX_CTL (HPS_ENET_RX_DV), .hps_io_hps_io_emac1_inst_TX_CTL (HPS_ENET_TX_EN), .hps_io_hps_io_emac1_inst_RX_CLK (HPS_ENET_RX_CLK), .hps_io_hps_io_emac1_inst_RXD1 (HPS_ENET_RX_DATA[1]), .hps_io_hps_io_emac1_inst_RXD2 (HPS_ENET_RX_DATA[2]), .hps_io_hps_io_emac1_inst_RXD3 (HPS_ENET_RX_DATA[3]), // I2C .hps_io_hps_io_i2c0_inst_SDA (HPS_I2C0_SDAT), .hps_io_hps_io_i2c0_inst_SCL (HPS_I2C0_SCLK), .hps_io_hps_io_i2c1_inst_SDA (HPS_I2C1_SDAT), .hps_io_hps_io_i2c1_inst_SCL (HPS_I2C1_SCLK), // Pushbutton .hps_io_hps_io_gpio_inst_GPIO54 (HPS_KEY), // LED .hps_io_hps_io_gpio_inst_GPIO53 (HPS_LED), // LTC .hps_io_hps_io_gpio_inst_GPIO40 (HPS_LTC_GPIO), // SD Card .hps_io_hps_io_sdio_inst_CMD (HPS_SD_CMD), .hps_io_hps_io_sdio_inst_D0 (HPS_SD_DATA[0]), .hps_io_hps_io_sdio_inst_D1 (HPS_SD_DATA[1]), .hps_io_hps_io_sdio_inst_CLK (HPS_SD_CLK), .hps_io_hps_io_sdio_inst_D2 (HPS_SD_DATA[2]), .hps_io_hps_io_sdio_inst_D3 (HPS_SD_DATA[3]), // SPI .hps_io_hps_io_spim1_inst_CLK (HPS_SPIM_CLK), .hps_io_hps_io_spim1_inst_MOSI (HPS_SPIM_MOSI), .hps_io_hps_io_spim1_inst_MISO (HPS_SPIM_MISO), .hps_io_hps_io_spim1_inst_SS0 (HPS_SPIM_SS), // UART .hps_io_hps_io_uart0_inst_RX (HPS_UART_RX), .hps_io_hps_io_uart0_inst_TX (HPS_UART_TX), // USB .hps_io_hps_io_gpio_inst_GPIO09 (HPS_CONV_USB_N), .hps_io_hps_io_usb1_inst_D0 (HPS_USB_DATA[0]), .hps_io_hps_io_usb1_inst_D1 (HPS_USB_DATA[1]), .hps_io_hps_io_usb1_inst_D2 (HPS_USB_DATA[2]), .hps_io_hps_io_usb1_inst_D3 (HPS_USB_DATA[3]), .hps_io_hps_io_usb1_inst_D4 (HPS_USB_DATA[4]), .hps_io_hps_io_usb1_inst_D5 (HPS_USB_DATA[5]), .hps_io_hps_io_usb1_inst_D6 (HPS_USB_DATA[6]), .hps_io_hps_io_usb1_inst_D7 (HPS_USB_DATA[7]), .hps_io_hps_io_usb1_inst_CLK (HPS_USB_CLKOUT), .hps_io_hps_io_usb1_inst_STP (HPS_USB_STP), .hps_io_hps_io_usb1_inst_DIR (HPS_USB_DIR), .hps_io_hps_io_usb1_inst_NXT (HPS_USB_NXT) ); endmodule 


Eu o trouxe especificamente na íntegra para enfatizar quanto código completamente desnecessário você precisa escrever neste caso. E se as pernas forem adicionadas ou removidas, esse código também precisará ser editado. Na verdade, as linhas


Mesmo texto:
 ... Computer_System The_System ( //////////////////////////////////// // FPGA Side //////////////////////////////////// // Global signals .system_pll_ref_clk_clk (CLOCK_50), ... 


e dê esse prefixo. Os autores acreditam que a hierarquia deve ser tal, somente esta e nenhuma outra. O sistema do processador não pode ser removido mais profundamente e não pode ser carregado.

Não devemos esperar misericórdia da natureza, aceite - nossa tarefa!


Realmente fizemos um trabalho tão puro para aturar esse assunto? Como um amigo meu gosta de dizer: “trabalho desnecessário é pior que embriaguez”, e a criação de uma camada desse tipo é um caso típico de trabalho desnecessário. Portanto, tentaremos contornar essa limitação. Lembre-se, ao chamar um programa JAVA de terceiros, o código substituiu algum script tcl, eu também o copiei para o diretório próximo ao arquivo sof? É a nossa salvação! É ele quem diz ao console do sistema que ações executar e é ele quem formata a resposta. a formatação é assim:

Mesmo texto:
 # PRINT OUT INSTANCE ID INFO FOR EVERYTHING: set i 0 foreach path [lsort -command compare_node_number [get_service_paths bytestream]] { # If this path corresponds to a JTAG UART, incr i if {[string match *$cable_name* $path ] && [string match *jtag_uart* [marker_get_type $path] ]} { puts "[marker_get_info $path] (INSTANCE_ID:$i)" incr i } } set i 0 foreach path [lsort -command compare_node_number [get_service_paths processor]] { # If this path corresponds to a NiosII, incr i if {[string match *$cable_name* $path ] && [string match *nios2* [marker_get_type $path] ]} { puts "[marker_get_info $path] (INSTANCE_ID:$i)" incr i } } 


O primeiro bloco formata informações sobre os blocos JTAG_UART, o segundo - sobre os núcleos do processador. Agora, se aqui adicionarmos linhas verticais ao fluxo de saída! Meu colega corrigiu esta seção da seguinte maneira:
 # PRINT OUT INSTANCE ID INFO FOR EVERYTHING: set i 0 foreach path [lsort -command compare_node_number [get_service_paths bytestream]] { # If this path corresponds to a JTAG UART, incr i if {[string match *$cable_name* $path ] && [string match *jtag_uart* [marker_get_type $path] ]} { set info [marker_get_info $path] if {[string first "|" $info] == -1} { set info [string map {"FULL_HPATH " "FULL_HPATH a:b|"} $info] } puts "$info (INSTANCE_ID:$i)" incr i } } set i 0 foreach path [lsort -command compare_node_number [get_service_paths processor]] { # If this path corresponds to a NiosII, incr i if {[string match *$cable_name* $path ] && [string match *nios2* [marker_get_type $path] ]} { set info [marker_get_info $path] if {[string first "|" $info] == -1} { set info [string map {"FULL_HPATH " "FULL_HPATH a:b|"} $info] } puts "$info (INSTANCE_ID:$i)" incr i } } 

Agora, se não houver traços, eles serão adicionados. E, finalmente, o programa funcionará não apenas com um sistema terrível, mas também com um sistema de processador idealmente escrito!

Configurando um projeto no Altera Monitor


Uffff. Só isso. O fim das goivagens, off-road e desleixado (embora, sobre off-road - isso não é preciso). Agora, novamente, os desenhos no artigo refletem as instruções para o trabalho! Temos um projeto para FPGAs, bem como um programa que cria e executa no Eclipse. Agora inicie o Altera Monitor e crie um projeto.



Criamos um catálogo com o projeto (coloquei-o separadamente do projeto para FPGA) e fornecemos o nome do projeto. Escolha também uma arquitetura de processador



O sistema que eu escolho é Sistema Personalizado. Você deve especificar meus arquivos * .sof e * .sopcinfo. Eu os seleciono nos diretórios de trabalho. Nosso sistema não precisa de um pré-carregador.



Selecione o tipo de programa Programa com suporte a driver de dispositivo e a biblioteca BSP será criada:



Até agora, existe apenas um arquivo de trabalho (ele foi criado no Eclipse). Aqui eu adiciono:



Na última janela, não mudo nada:



Concordamos com o download do arquivo sof:



Se apenas instalamos o software, mudamos para o modo de fonte. Em seguida, ele já estará ativado (mostrarei como é o menu quando tudo estiver ativado, também haverá um item para inclusão).



Eu tenho o programa C mais simples:
 #include "sys/alt_stdio.h" int main() { alt_putstr("Hello from Nios II!\n"); volatile int i=0; i += 1; i += 2; i += 3; i += 4; i += 5; i += 6; i += 7; i += 8; i += 9; i += 10; i += 11; i += 12; /* Event loop never exits. */ while (1); return 0; } 

Estou tentando coletar:



Eu recebo um erro:
c: /intelfpga/17.1/nios2eds/bin/gnu/h-x86_64-mingw32/bin /../ lib / gcc / nios2-elf / 5.3.0 /../../../../ .. /H-x86_64-mingw32/nios2-elf/bin/ld.exe: código da região excedido em 15888 bytes

Isso ocorre porque eu não adicionei SDRAM ao sistema, limitei-o à memória FPGA interna. Mas por que tudo se encaixava no Eclipse, mas não aqui? Porque eu escolhi o BSP lá com o sufixo Small, mas aqui eu fui automaticamente feito um pacote regular. Portanto, abra o arquivo: C: \ Work \ Play2 \ BSP \ settings.bsp

E começamos o ajuste manual.





Reconstrua o BSP:



E novamente coletamos o projeto. Desta vez com sucesso. Agora carregue-o:



Finalmente, o verdadeiro traço


Você não esqueceu por que eu faço tudo isso? Eu faço isso para rastrear. Deve ser ativado. Para fazer isso, vá para a guia Rastreio e selecione Ativar Rastreio no menu de contexto:



Vou colocar um ponto de interrupção no final da função main () na guia Desmontagem (como é bom o montador RISC cuidar do terrível montador de pilha no qual o código Java é convertido!)

Aqui está o começo da função principal:



Role um pouco e coloque um ponto de interrupção aqui:



Começamos, esperamos uma parada e vamos para a guia Rastreio.

Em geral, nem tudo está muito bem. No começo, havia obviamente algum tipo de expectativa (tivemos uma conclusão no JTAG lá, então é uma coisa legítima):



No final - algum outro código ... Mas não vejo o código da função principal! Aqui está o fim:



Eu nem sei o que dizer. Mas, enfim, se você não colocar um, mas dois pontos de interrupção (no início e no final da função principal), depois de executar do primeiro para o segundo, a imagem será decente:



Breves conclusões


Então, descobrimos que é bem possível descobrir como um site específico funcionou. Portanto, o tópico do artigo ("... como o processador chegou a essa vida") é divulgado. É mais interessante como todos aqueles cujos problemas tiveram que ser resolvidos para obter um resultado chegaram a essa vida? E é uma pena que até agora eu não tenha sido capaz de determinar quantas barras uma equipe em particular completou. A partir de trechos da documentação, fica claro que isso parece ser tecnicamente possível, mas que software permitirá que isso seja feito não está claro. Há uma opinião de que o documento Analisando e Depurando Projetos com o System Console , que eu precisei ler ao analisar o script tcl, nos ajudará. Ele possui um tablet interessante. Tabela 10-15: Comandos do sistema de rastreamento , mas, pessoalmente, não tenho tempo para um estudo detalhado desse assunto. Mas talvez seja tão importante para alguém que ele implemente tudo. Esses comandos estão incluídos nos scripts tcl.

Bem, nos artigos a seguir, as medições terão que ser feitas da maneira antiga, com um osciloscópio.

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


All Articles